diff options
author | Stan Hu <stanhu@gmail.com> | 2018-07-12 15:21:37 +0300 |
---|---|---|
committer | Stan Hu <stanhu@gmail.com> | 2018-07-12 15:21:37 +0300 |
commit | 2d3fd6a142d286bb7d6355ed3601e618bc246112 (patch) | |
tree | 1b1c99150ac063d3d3e90583ce7b3c657e93ad5a | |
parent | bb98ed112c509c6265ba4dff81d7987c52a8748c (diff) | |
parent | eddf34f4af8a2cfdcea2586a91b0fc38a7ba0277 (diff) |
Merge branch 'master' into sh-support-bitbucket-server-import
791 files changed, 7695 insertions, 5177 deletions
diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..f1c41c9bb76 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +Dangerfile gitlab-language=ruby diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 610a5ecba6d..137c26d7dae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -348,6 +348,24 @@ retrieve-tests-metadata: - wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH - '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}' +danger-review: + image: registry.gitlab.com/gitlab-org/gitaly/dangercontainer:latest + stage: prepare + before_script: + - source scripts/utils.sh + - retry gem install danger --no-ri --no-rdoc + cache: {} + only: + refs: + - branches@gitlab-org/gitlab-ce + - branches@gitlab-org/gitlab-ee + except: + variables: + - $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/ + script: + - git version + - danger --fail-on-errors=true + update-tests-metadata: <<: *tests-metadata-state <<: *only-canonical-masters diff --git a/Dangerfile b/Dangerfile new file mode 100644 index 00000000000..84b72673c50 --- /dev/null +++ b/Dangerfile @@ -0,0 +1,6 @@ +danger.import_dangerfile(path: 'danger/metadata') +danger.import_dangerfile(path: 'danger/changes_size') +danger.import_dangerfile(path: 'danger/changelog') +danger.import_dangerfile(path: 'danger/specs') +danger.import_dangerfile(path: 'danger/gemfile') +danger.import_dangerfile(path: 'danger/database') diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 5af665a17e0..e23e3fd2982 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.111.0 +0.112.0 diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index b7f8ee41e69..69adf3456f8 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -7.1.4 +7.1.5 diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js index 1638e09132b..b0c85c2572e 100644 --- a/app/assets/javascripts/confirm_danger_modal.js +++ b/app/assets/javascripts/confirm_danger_modal.js @@ -2,13 +2,16 @@ import $ from 'jquery'; import { rstrip } from './lib/utils/common_utils'; function openConfirmDangerModal($form, text) { + const $input = $('.js-confirm-danger-input'); + $input.val(''); + $('.js-confirm-text').text(text || ''); - $('.js-confirm-danger-input').val(''); $('#modal-confirm-danger').modal('show'); const confirmTextMatch = $('.js-confirm-danger-match').text(); const $submit = $('.js-confirm-danger-submit'); $submit.disable(); + $input.focus(); $('.js-confirm-danger-input').off('input').on('input', function handleInput() { const confirmText = rstrip($(this).val()); diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 060386c3ecb..a61e368249a 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -31,9 +31,6 @@ export default { }; }, computed: { - isDiscussionsExpanded() { - return true; // TODO: @fatihacet - Fix this. - }, isCollapsed() { return this.file.collapsed || false; }, @@ -131,7 +128,6 @@ export default { :diff-file="file" :collapsible="true" :expanded="!isCollapsed" - :discussions-expanded="isDiscussionsExpanded" :add-merge-request-buttons="true" class="js-file-title file-title" @toggleFile="handleToggle" diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 1957698c6c1..c5abd0a9568 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -1,5 +1,6 @@ <script> import _ from 'underscore'; +import { mapActions, mapGetters } from 'vuex'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import Icon from '~/vue_shared/components/icon.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; @@ -38,11 +39,6 @@ export default { required: false, default: true, }, - discussionsExpanded: { - type: Boolean, - required: false, - default: true, - }, currentUser: { type: Object, required: true, @@ -54,6 +50,10 @@ export default { }; }, computed: { + ...mapGetters('diffs', ['diffHasExpandedDiscussions']), + hasExpandedDiscussions() { + return this.diffHasExpandedDiscussions(this.diffFile); + }, icon() { if (this.diffFile.submodule) { return 'archive'; @@ -88,9 +88,6 @@ export default { collapseIcon() { return this.expanded ? 'chevron-down' : 'chevron-right'; }, - isDiscussionsExpanded() { - return this.discussionsExpanded && this.expanded; - }, viewFileButtonText() { const truncatedContentSha = _.escape(truncateSha(this.diffFile.contentSha)); return sprintf( @@ -113,7 +110,8 @@ export default { }, }, methods: { - handleToggle(e, checkTarget) { + ...mapActions('diffs', ['toggleFileDiscussions']), + handleToggleFile(e, checkTarget) { if ( !checkTarget || e.target === this.$refs.header || @@ -125,6 +123,9 @@ export default { showForkMessage() { this.$emit('showForkMessage'); }, + handleToggleDiscussions() { + this.toggleFileDiscussions(this.diffFile); + }, }, }; </script> @@ -133,7 +134,7 @@ export default { <div ref="header" class="js-file-title file-title file-title-flex-parent" - @click="handleToggle($event, true)" + @click="handleToggleFile($event, true)" > <div class="file-header-content"> <icon @@ -216,10 +217,11 @@ export default { v-if="diffFile.blob && diffFile.blob.readableText" > <button - :class="{ active: isDiscussionsExpanded }" + :class="{ active: hasExpandedDiscussions }" :title="s__('MergeRequests|Toggle comments for this file')" - class="btn js-toggle-diff-comments" + class="js-btn-vue-toggle-comments btn" type="button" + @click="handleToggleDiscussions" > <icon name="comment" /> </button> diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 5e0fd5109bb..27001142257 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -82,14 +82,32 @@ export const expandAllFiles = ({ commit }) => { commit(types.EXPAND_ALL_FILES); }; -export default { - setBaseConfig, - fetchDiffFiles, - setInlineDiffViewType, - setParallelDiffViewType, - showCommentForm, - cancelCommentForm, - loadMoreLines, - loadCollapsedDiff, - expandAllFiles, +/** + * Toggles the file discussions after user clicked on the toggle discussions button. + * + * Gets the discussions for the provided diff. + * + * If all discussions are expanded, it will collapse all of them + * If all discussions are collapsed, it will expand all of them + * If some discussions are open and others closed, it will expand the closed ones. + * + * @param {Object} diff + */ +export const toggleFileDiscussions = ({ getters, dispatch }, diff) => { + const discussions = getters.getDiffFileDiscussions(diff); + const shouldCloseAll = getters.diffHasAllExpandedDiscussions(diff); + const shouldExpandAll = getters.diffHasAllCollpasedDiscussions(diff); + + discussions.forEach(discussion => { + const data = { discussionId: discussion.id }; + + if (shouldCloseAll) { + dispatch('collapseDiscussion', data, { root: true }); + } else if (shouldExpandAll || (!shouldCloseAll && !shouldExpandAll && !discussion.expanded)) { + dispatch('expandDiscussion', data, { root: true }); + } + }); }; + +// prevent babel-plugin-rewire from generating an invalid default during karma tests +export default () => {}; diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index f3c2d7427e7..f89acb73ed8 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -1,3 +1,4 @@ +import _ from 'underscore'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '../constants'; export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW_TYPE; @@ -8,5 +9,52 @@ export const areAllFilesCollapsed = state => state.diffFiles.every(file => file. export const commitId = state => (state.commit && state.commit.id ? state.commit.id : null); -// prevent babel-plugin-rewire from generating an invalid default during karma tests +/** + * Checks if the diff has all discussions expanded + * @param {Object} diff + * @returns {Boolean} + */ +export const diffHasAllExpandedDiscussions = (state, getters) => diff => { + const discussions = getters.getDiffFileDiscussions(diff); + + return (discussions.length && discussions.every(discussion => discussion.expanded)) || false; +}; + +/** + * Checks if the diff has all discussions collpased + * @param {Object} diff + * @returns {Boolean} + */ +export const diffHasAllCollpasedDiscussions = (state, getters) => diff => { + const discussions = getters.getDiffFileDiscussions(diff); + + return (discussions.length && discussions.every(discussion => !discussion.expanded)) || false; +}; + +/** + * Checks if the diff has any open discussions + * @param {Object} diff + * @returns {Boolean} + */ +export const diffHasExpandedDiscussions = (state, getters) => diff => { + const discussions = getters.getDiffFileDiscussions(diff); + + return ( + (discussions.length && discussions.find(discussion => discussion.expanded) !== undefined) || + false + ); +}; + +/** + * Returns an array with the discussions of the given diff + * @param {Object} diff + * @returns {Array} + */ +export const getDiffFileDiscussions = (state, getters, rootState, rootGetters) => diff => + rootGetters.discussions.filter( + discussion => + discussion.diff_discussion && _.isEqual(discussion.diff_file.file_hash, diff.fileHash), + ) || []; + +// prevent babel-plugin-rewire from generating an invalid default during karma∂ tests export default () => {}; diff --git a/app/assets/javascripts/diffs/store/index.js b/app/assets/javascripts/diffs/store/index.js deleted file mode 100644 index e6aa8f5b12a..00000000000 --- a/app/assets/javascripts/diffs/store/index.js +++ /dev/null @@ -1,11 +0,0 @@ -import Vue from 'vue'; -import Vuex from 'vuex'; -import diffsModule from './modules'; - -Vue.use(Vuex); - -export default new Vuex.Store({ - modules: { - diffs: diffsModule, - }, -}); diff --git a/app/assets/javascripts/diffs/store/modules/index.js b/app/assets/javascripts/diffs/store/modules/index.js index 90505f83b60..20d1ebbe049 100644 --- a/app/assets/javascripts/diffs/store/modules/index.js +++ b/app/assets/javascripts/diffs/store/modules/index.js @@ -1,4 +1,4 @@ -import actions from '../actions'; +import * as actions from '../actions'; import * as getters from '../getters'; import mutations from '../mutations'; import createState from './diff_state'; diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue index e3652fe739e..63d83e307ee 100644 --- a/app/assets/javascripts/environments/components/environment_actions.vue +++ b/app/assets/javascripts/environments/components/environment_actions.vue @@ -1,50 +1,50 @@ <script> - import Icon from '~/vue_shared/components/icon.vue'; - import eventHub from '../event_hub'; - import loadingIcon from '../../vue_shared/components/loading_icon.vue'; - import tooltip from '../../vue_shared/directives/tooltip'; +import Icon from '~/vue_shared/components/icon.vue'; +import eventHub from '../event_hub'; +import loadingIcon from '../../vue_shared/components/loading_icon.vue'; +import tooltip from '../../vue_shared/directives/tooltip'; - export default { - directives: { - tooltip, +export default { + directives: { + tooltip, + }, + components: { + loadingIcon, + Icon, + }, + props: { + actions: { + type: Array, + required: false, + default: () => [], }, - components: { - loadingIcon, - Icon, + }, + data() { + return { + isLoading: false, + }; + }, + computed: { + title() { + return 'Deploy to...'; }, - props: { - actions: { - type: Array, - required: false, - default: () => [], - }, - }, - data() { - return { - isLoading: false, - }; - }, - computed: { - title() { - return 'Deploy to...'; - }, - }, - methods: { - onClickAction(endpoint) { - this.isLoading = true; + }, + methods: { + onClickAction(endpoint) { + this.isLoading = true; - eventHub.$emit('postAction', endpoint); - }, + eventHub.$emit('postAction', { endpoint }); + }, - isActionDisabled(action) { - if (action.playable === undefined) { - return false; - } + isActionDisabled(action) { + if (action.playable === undefined) { + return false; + } - return !action.playable; - }, + return !action.playable; }, - }; + }, +}; </script> <template> <div @@ -61,10 +61,7 @@ data-toggle="dropdown" > <span> - <icon - :size="12" - name="play" - /> + <icon name="play" /> <i class="fa fa-caret-down" aria-hidden="true" @@ -85,10 +82,6 @@ class="js-manual-action-link no-btn btn" @click="onClickAction(action.play_path)" > - <icon - :size="12" - name="play" - /> <span> {{ action.name }} </span> diff --git a/app/assets/javascripts/environments/components/environment_external_url.vue b/app/assets/javascripts/environments/components/environment_external_url.vue index 68195225d50..7446196de13 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.vue +++ b/app/assets/javascripts/environments/components/environment_external_url.vue @@ -1,30 +1,30 @@ <script> - import Icon from '~/vue_shared/components/icon.vue'; - import tooltip from '../../vue_shared/directives/tooltip'; - import { s__ } from '../../locale'; +import Icon from '~/vue_shared/components/icon.vue'; +import tooltip from '../../vue_shared/directives/tooltip'; +import { s__ } from '../../locale'; - /** - * Renders the external url link in environments table. - */ - export default { - components: { - Icon, +/** + * Renders the external url link in environments table. + */ +export default { + components: { + Icon, + }, + directives: { + tooltip, + }, + props: { + externalUrl: { + type: String, + required: true, }, - directives: { - tooltip, + }, + computed: { + title() { + return s__('Environments|Open live environment'); }, - props: { - externalUrl: { - type: String, - required: true, - }, - }, - computed: { - title() { - return s__('Environments|Open'); - }, - }, - }; + }, +}; </script> <template> <a @@ -37,9 +37,6 @@ target="_blank" rel="noopener noreferrer nofollow" > - <icon - :size="12" - name="external-link" - /> + <icon name="external-link" /> </a> </template> diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index 5ecdccf63ad..39f3790a286 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -1,429 +1,450 @@ <script> - import Timeago from 'timeago.js'; - import _ from 'underscore'; - import tooltip from '~/vue_shared/directives/tooltip'; - import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; - import { humanize } from '~/lib/utils/text_utility'; - import ActionsComponent from './environment_actions.vue'; - import ExternalUrlComponent from './environment_external_url.vue'; - import StopComponent from './environment_stop.vue'; - 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.vue'; - import eventHub from '../event_hub'; - - /** - * Envrionment Item Component - * - * Renders a table row for each environment. - */ - const timeagoInstance = new Timeago(); - - export default { - components: { - UserAvatarLink, - CommitComponent, - ActionsComponent, - ExternalUrlComponent, - StopComponent, - RollbackComponent, - TerminalButtonComponent, - MonitoringButtonComponent, +import Timeago from 'timeago.js'; +import _ from 'underscore'; +import tooltip from '~/vue_shared/directives/tooltip'; +import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; +import { humanize } from '~/lib/utils/text_utility'; +import ActionsComponent from './environment_actions.vue'; +import ExternalUrlComponent from './environment_external_url.vue'; +import StopComponent from './environment_stop.vue'; +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.vue'; +import eventHub from '../event_hub'; + +/** + * Envrionment Item Component + * + * Renders a table row for each environment. + */ +const timeagoInstance = new Timeago(); + +export default { + components: { + UserAvatarLink, + CommitComponent, + ActionsComponent, + ExternalUrlComponent, + StopComponent, + RollbackComponent, + TerminalButtonComponent, + MonitoringButtonComponent, + }, + + directives: { + tooltip, + }, + + props: { + model: { + type: Object, + required: true, + default: () => ({}), }, - directives: { - tooltip, + canCreateDeployment: { + type: Boolean, + required: false, + default: false, }, - props: { - model: { - type: Object, - required: true, - default: () => ({}), - }, - - canCreateDeployment: { - type: Boolean, - required: false, - default: false, - }, - - canReadEnvironment: { - type: Boolean, - required: false, - default: false, - }, + canReadEnvironment: { + type: Boolean, + required: false, + default: false, + }, + }, + + computed: { + /** + * Verifies if `last_deployment` key exists in the current Envrionment. + * This key is required to render most of the html - this method works has + * an helper. + * + * @returns {Boolean} + */ + hasLastDeploymentKey() { + if (this.model && this.model.last_deployment && !_.isEmpty(this.model.last_deployment)) { + return true; + } + return false; + }, + + /** + * Verifies is the given environment has manual actions. + * Used to verify if we should render them or nor. + * + * @returns {Boolean|Undefined} + */ + hasManualActions() { + return ( + this.model && + this.model.last_deployment && + this.model.last_deployment.manual_actions && + this.model.last_deployment.manual_actions.length > 0 + ); + }, + + /** + * Returns whether the environment can be stopped. + * + * @returns {Boolean} + */ + canStopEnvironment() { + return this.model && this.model.can_stop; + }, + + /** + * Verifies if the `deployable` key is present in `last_deployment` key. + * Used to verify whether we should or not render the rollback partial. + * + * @returns {Boolean|Undefined} + */ + canRetry() { + return ( + this.model && + this.hasLastDeploymentKey && + this.model.last_deployment && + this.model.last_deployment.deployable + ); + }, + + /** + * Verifies if the date to be shown is present. + * + * @returns {Boolean|Undefined} + */ + canShowDate() { + return ( + this.model && + this.model.last_deployment && + this.model.last_deployment.deployable && + this.model.last_deployment.deployable !== undefined + ); + }, + + /** + * Human readable date. + * + * @returns {String} + */ + createdDate() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.deployable && + this.model.last_deployment.deployable.created_at + ) { + return timeagoInstance.format(this.model.last_deployment.deployable.created_at); + } + return ''; + }, + + /** + * Returns the manual actions with the name parsed. + * + * @returns {Array.<Object>|Undefined} + */ + manualActions() { + if (this.hasManualActions) { + return this.model.last_deployment.manual_actions.map(action => { + const parsedAction = { + name: humanize(action.name), + play_path: action.play_path, + playable: action.playable, + }; + return parsedAction; + }); + } + return []; + }, + + /** + * Builds the string used in the user image alt attribute. + * + * @returns {String} + */ + userImageAltDescription() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.user && + this.model.last_deployment.user.username + ) { + return `${this.model.last_deployment.user.username}'s avatar'`; + } + return ''; + }, + + /** + * If provided, returns the commit tag. + * + * @returns {String|Undefined} + */ + commitTag() { + if (this.model && this.model.last_deployment && this.model.last_deployment.tag) { + return this.model.last_deployment.tag; + } + return undefined; + }, + + /** + * If provided, returns the commit ref. + * + * @returns {Object|Undefined} + */ + commitRef() { + if (this.model && this.model.last_deployment && this.model.last_deployment.ref) { + return this.model.last_deployment.ref; + } + return undefined; + }, + + /** + * If provided, returns the commit url. + * + * @returns {String|Undefined} + */ + commitUrl() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.commit_path + ) { + return this.model.last_deployment.commit.commit_path; + } + return undefined; + }, + + /** + * If provided, returns the commit short sha. + * + * @returns {String|Undefined} + */ + commitShortSha() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.short_id + ) { + return this.model.last_deployment.commit.short_id; + } + return undefined; + }, + + /** + * If provided, returns the commit title. + * + * @returns {String|Undefined} + */ + commitTitle() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.title + ) { + return this.model.last_deployment.commit.title; + } + return undefined; + }, + + /** + * If provided, returns the commit tag. + * + * @returns {Object|Undefined} + */ + commitAuthor() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.commit && + this.model.last_deployment.commit.author + ) { + return this.model.last_deployment.commit.author; + } + + return undefined; + }, + + /** + * Verifies if the `retry_path` key is present and returns its value. + * + * @returns {String|Undefined} + */ + retryUrl() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.deployable && + this.model.last_deployment.deployable.retry_path + ) { + return this.model.last_deployment.deployable.retry_path; + } + return undefined; + }, + + /** + * Verifies if the `last?` key is present and returns its value. + * + * @returns {Boolean|Undefined} + */ + isLastDeployment() { + return this.model && this.model.last_deployment && this.model.last_deployment['last?']; + }, + + /** + * Builds the name of the builds needed to display both the name and the id. + * + * @returns {String} + */ + buildName() { + if (this.model && this.model.last_deployment && this.model.last_deployment.deployable) { + const { deployable } = this.model.last_deployment; + return `${deployable.name} #${deployable.id}`; + } + return ''; + }, + + /** + * Builds the needed string to show the internal id. + * + * @returns {String} + */ + deploymentInternalId() { + if (this.model && this.model.last_deployment && this.model.last_deployment.iid) { + return `#${this.model.last_deployment.iid}`; + } + return ''; }, - computed: { - /** - * Verifies if `last_deployment` key exists in the current Envrionment. - * This key is required to render most of the html - this method works has - * an helper. - * - * @returns {Boolean} - */ - hasLastDeploymentKey() { - if (this.model && - this.model.last_deployment && - !_.isEmpty(this.model.last_deployment)) { - return true; - } - return false; - }, - - /** - * Verifies is the given environment has manual actions. - * Used to verify if we should render them or nor. - * - * @returns {Boolean|Undefined} - */ - hasManualActions() { - return this.model && - this.model.last_deployment && - this.model.last_deployment.manual_actions && - this.model.last_deployment.manual_actions.length > 0; - }, - - /** - * Returns the value of the `stop_action?` key provided in the response. - * - * @returns {Boolean} - */ - hasStopAction() { - return this.model && this.model['stop_action?']; - }, - - /** - * Verifies if the `deployable` key is present in `last_deployment` key. - * Used to verify whether we should or not render the rollback partial. - * - * @returns {Boolean|Undefined} - */ - canRetry() { - return this.model && - this.hasLastDeploymentKey && - this.model.last_deployment && - this.model.last_deployment.deployable; - }, - - /** - * Verifies if the date to be shown is present. - * - * @returns {Boolean|Undefined} - */ - canShowDate() { - return this.model && - this.model.last_deployment && - this.model.last_deployment.deployable && - this.model.last_deployment.deployable !== undefined; - }, - - /** - * Human readable date. - * - * @returns {String} - */ - createdDate() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.deployable && - this.model.last_deployment.deployable.created_at) { - return timeagoInstance.format(this.model.last_deployment.deployable.created_at); - } - return ''; - }, - - /** - * Returns the manual actions with the name parsed. - * - * @returns {Array.<Object>|Undefined} - */ - manualActions() { - if (this.hasManualActions) { - return this.model.last_deployment.manual_actions.map((action) => { - const parsedAction = { - name: humanize(action.name), - play_path: action.play_path, - playable: action.playable, - }; - return parsedAction; - }); - } - return []; - }, - - /** - * Builds the string used in the user image alt attribute. - * - * @returns {String} - */ - userImageAltDescription() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.user && - this.model.last_deployment.user.username) { - return `${this.model.last_deployment.user.username}'s avatar'`; - } - return ''; - }, - - /** - * If provided, returns the commit tag. - * - * @returns {String|Undefined} - */ - commitTag() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.tag) { - return this.model.last_deployment.tag; - } - return undefined; - }, - - /** - * If provided, returns the commit ref. - * - * @returns {Object|Undefined} - */ - commitRef() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.ref) { - return this.model.last_deployment.ref; - } - return undefined; - }, - - /** - * If provided, returns the commit url. - * - * @returns {String|Undefined} - */ - commitUrl() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.commit && - this.model.last_deployment.commit.commit_path) { - return this.model.last_deployment.commit.commit_path; - } - return undefined; - }, - - /** - * If provided, returns the commit short sha. - * - * @returns {String|Undefined} - */ - commitShortSha() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.commit && - this.model.last_deployment.commit.short_id) { - return this.model.last_deployment.commit.short_id; - } - return undefined; - }, - - /** - * If provided, returns the commit title. - * - * @returns {String|Undefined} - */ - commitTitle() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.commit && - this.model.last_deployment.commit.title) { - return this.model.last_deployment.commit.title; - } - return undefined; - }, - - /** - * If provided, returns the commit tag. - * - * @returns {Object|Undefined} - */ - commitAuthor() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.commit && - this.model.last_deployment.commit.author) { - return this.model.last_deployment.commit.author; - } - - return undefined; - }, - - /** - * Verifies if the `retry_path` key is present and returns its value. - * - * @returns {String|Undefined} - */ - retryUrl() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.deployable && - this.model.last_deployment.deployable.retry_path) { - return this.model.last_deployment.deployable.retry_path; - } - return undefined; - }, - - /** - * Verifies if the `last?` key is present and returns its value. - * - * @returns {Boolean|Undefined} - */ - isLastDeployment() { - return this.model && this.model.last_deployment && - this.model.last_deployment['last?']; - }, - - /** - * Builds the name of the builds needed to display both the name and the id. - * - * @returns {String} - */ - buildName() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.deployable) { - const { deployable } = this.model.last_deployment; - return `${deployable.name} #${deployable.id}`; - } - return ''; - }, - - /** - * Builds the needed string to show the internal id. - * - * @returns {String} - */ - deploymentInternalId() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.iid) { - return `#${this.model.last_deployment.iid}`; - } - return ''; - }, - - /** - * Verifies if the user object is present under last_deployment object. - * - * @returns {Boolean} - */ - deploymentHasUser() { - return this.model && - !_.isEmpty(this.model.last_deployment) && - !_.isEmpty(this.model.last_deployment.user); - }, - - /** - * Returns the user object nested with the last_deployment object. - * Used to render the template. - * - * @returns {Object} - */ - deploymentUser() { - if (this.model && - !_.isEmpty(this.model.last_deployment) && - !_.isEmpty(this.model.last_deployment.user)) { - return this.model.last_deployment.user; - } - return {}; - }, - - /** - * Verifies if the build name column should be rendered by verifing - * if all the information needed is present - * and if the environment is not a folder. - * - * @returns {Boolean} - */ - shouldRenderBuildName() { - return !this.model.isFolder && - !_.isEmpty(this.model.last_deployment) && - !_.isEmpty(this.model.last_deployment.deployable); - }, - - /** - * Verifies the presence of all the keys needed to render the buil_path. - * - * @return {String} - */ - buildPath() { - if (this.model && - this.model.last_deployment && - this.model.last_deployment.deployable && - this.model.last_deployment.deployable.build_path) { - return this.model.last_deployment.deployable.build_path; - } - - return ''; - }, - - /** - * Verifies the presence of all the keys needed to render the external_url. - * - * @return {String} - */ - externalURL() { - if (this.model && this.model.external_url) { - return this.model.external_url; - } - - return ''; - }, - - /** - * Verifies if deplyment internal ID should be rendered by verifing - * if all the information needed is present - * and if the environment is not a folder. - * - * @returns {Boolean} - */ - shouldRenderDeploymentID() { - return !this.model.isFolder && - !_.isEmpty(this.model.last_deployment) && - this.model.last_deployment.iid !== undefined; - }, - - environmentPath() { - if (this.model && this.model.environment_path) { - return this.model.environment_path; - } - - return ''; - }, - - monitoringUrl() { - if (this.model && this.model.metrics_path) { - return this.model.metrics_path; - } - - return ''; - }, - - displayEnvironmentActions() { - return this.hasManualActions || - this.externalURL || - this.monitoringUrl || - this.hasStopAction || - this.canRetry; - }, + /** + * Verifies if the user object is present under last_deployment object. + * + * @returns {Boolean} + */ + deploymentHasUser() { + return ( + this.model && + !_.isEmpty(this.model.last_deployment) && + !_.isEmpty(this.model.last_deployment.user) + ); }, - methods: { - onClickFolder() { - eventHub.$emit('toggleFolder', this.model); - }, + /** + * Returns the user object nested with the last_deployment object. + * Used to render the template. + * + * @returns {Object} + */ + deploymentUser() { + if ( + this.model && + !_.isEmpty(this.model.last_deployment) && + !_.isEmpty(this.model.last_deployment.user) + ) { + return this.model.last_deployment.user; + } + return {}; }, - }; + + /** + * Verifies if the build name column should be rendered by verifing + * if all the information needed is present + * and if the environment is not a folder. + * + * @returns {Boolean} + */ + shouldRenderBuildName() { + return ( + !this.model.isFolder && + !_.isEmpty(this.model.last_deployment) && + !_.isEmpty(this.model.last_deployment.deployable) + ); + }, + + /** + * Verifies the presence of all the keys needed to render the buil_path. + * + * @return {String} + */ + buildPath() { + if ( + this.model && + this.model.last_deployment && + this.model.last_deployment.deployable && + this.model.last_deployment.deployable.build_path + ) { + return this.model.last_deployment.deployable.build_path; + } + + return ''; + }, + + /** + * Verifies the presence of all the keys needed to render the external_url. + * + * @return {String} + */ + externalURL() { + if (this.model && this.model.external_url) { + return this.model.external_url; + } + + return ''; + }, + + /** + * Verifies if deplyment internal ID should be rendered by verifing + * if all the information needed is present + * and if the environment is not a folder. + * + * @returns {Boolean} + */ + shouldRenderDeploymentID() { + return ( + !this.model.isFolder && + !_.isEmpty(this.model.last_deployment) && + this.model.last_deployment.iid !== undefined + ); + }, + + environmentPath() { + if (this.model && this.model.environment_path) { + return this.model.environment_path; + } + + return ''; + }, + + monitoringUrl() { + if (this.model && this.model.metrics_path) { + return this.model.metrics_path; + } + + return ''; + }, + + displayEnvironmentActions() { + return ( + this.hasManualActions || + this.externalURL || + this.monitoringUrl || + this.canStopEnvironment || + this.canRetry + ); + }, + }, + + methods: { + onClickFolder() { + eventHub.$emit('toggleFolder', this.model); + }, + }, +}; </script> <template> <div @@ -580,11 +601,6 @@ class="btn-group table-action-buttons" role="group"> - <actions-component - v-if="hasManualActions && canCreateDeployment" - :actions="manualActions" - /> - <external-url-component v-if="externalURL && canReadEnvironment" :external-url="externalURL" @@ -595,21 +611,26 @@ :monitoring-url="monitoringUrl" /> + <actions-component + v-if="hasManualActions && canCreateDeployment" + :actions="manualActions" + /> + <terminal-button-component v-if="model && model.terminal_path" :terminal-path="model.terminal_path" /> - <stop-component - v-if="hasStopAction && canCreateDeployment" - :stop-url="model.stop_path" - /> - <rollback-component v-if="canRetry && canCreateDeployment" :is-last-deployment="isLastDeployment" :retry-url="retryUrl" /> + + <stop-component + v-if="canStopEnvironment" + :environment="model" + /> </div> </div> </div> diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue index 947e8c901e9..ccc8419ca6d 100644 --- a/app/assets/javascripts/environments/components/environment_monitoring.vue +++ b/app/assets/javascripts/environments/components/environment_monitoring.vue @@ -1,29 +1,29 @@ <script> - /** - * Renders the Monitoring (Metrics) link in environments table. - */ - import Icon from '~/vue_shared/components/icon.vue'; - import tooltip from '../../vue_shared/directives/tooltip'; +/** + * Renders the Monitoring (Metrics) link in environments table. + */ +import Icon from '~/vue_shared/components/icon.vue'; +import tooltip from '../../vue_shared/directives/tooltip'; - export default { - components: { - Icon, +export default { + components: { + Icon, + }, + directives: { + tooltip, + }, + props: { + monitoringUrl: { + type: String, + required: true, }, - directives: { - tooltip, + }, + computed: { + title() { + return 'Monitoring'; }, - props: { - monitoringUrl: { - type: String, - required: true, - }, - }, - computed: { - title() { - return 'Monitoring'; - }, - }, - }; + }, +}; </script> <template> <a @@ -35,9 +35,6 @@ data-container="body" rel="noopener noreferrer nofollow" > - <icon - :size="12" - name="chart" - /> + <icon name="chart" /> </a> </template> diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue index 310835c5ea9..4deeef4beb9 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.vue +++ b/app/assets/javascripts/environments/components/environment_rollback.vue @@ -1,56 +1,74 @@ <script> - /** - * Renders Rollback or Re deploy button in environments table depending - * of the provided property `isLastDeployment`. - * - * Makes a post request when the button is clicked. - */ - import eventHub from '../event_hub'; - import loadingIcon from '../../vue_shared/components/loading_icon.vue'; - - export default { - components: { - loadingIcon, +/** + * Renders Rollback or Re deploy button in environments table depending + * of the provided property `isLastDeployment`. + * + * Makes a post request when the button is clicked. + */ +import { s__ } from '~/locale'; +import Icon from '~/vue_shared/components/icon.vue'; +import tooltip from '~/vue_shared/directives/tooltip'; +import eventHub from '../event_hub'; +import LoadingIcon from '../../vue_shared/components/loading_icon.vue'; + +export default { + components: { + Icon, + LoadingIcon, + }, + + directives: { + tooltip, + }, + + props: { + retryUrl: { + type: String, + default: '', }, - props: { - retryUrl: { - type: String, - default: '', - }, - - isLastDeployment: { - type: Boolean, - default: true, - }, + + isLastDeployment: { + type: Boolean, + default: true, }, - data() { - return { - isLoading: false, - }; + }, + data() { + return { + isLoading: false, + }; + }, + + computed: { + title() { + return this.isLastDeployment ? s__('Environments|Re-deploy to environment') : s__('Environments|Rollback environment'); }, - methods: { - onClick() { - this.isLoading = true; + }, + + methods: { + onClick() { + this.isLoading = true; - eventHub.$emit('postAction', this.retryUrl); - }, + eventHub.$emit('postAction', { endpoint: this.retryUrl }); }, - }; + }, +}; </script> <template> <button + v-tooltip :disabled="isLoading" + :title="title" type="button" class="btn d-none d-sm-none d-md-block" @click="onClick" > - <span v-if="isLastDeployment"> - {{ s__("Environments|Re-deploy") }} - </span> - <span v-else> - {{ s__("Environments|Rollback") }} - </span> + <icon + v-if="isLastDeployment" + name="repeat" /> + <icon + v-else + name="redo"/> <loading-icon v-if="isLoading" /> </button> diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue index eba58bedd6d..a814b3405f5 100644 --- a/app/assets/javascripts/environments/components/environment_stop.vue +++ b/app/assets/javascripts/environments/components/environment_stop.vue @@ -1,72 +1,78 @@ <script> - /** - * Renders the stop "button" that allows stop an environment. - * Used in environments table. - */ +/** + * Renders the stop "button" that allows stop an environment. + * Used in environments table. + */ - import $ from 'jquery'; - import eventHub from '../event_hub'; - import loadingIcon from '../../vue_shared/components/loading_icon.vue'; - import tooltip from '../../vue_shared/directives/tooltip'; +import $ from 'jquery'; +import Icon from '~/vue_shared/components/icon.vue'; +import { s__ } from '~/locale'; +import eventHub from '../event_hub'; +import LoadingButton from '../../vue_shared/components/loading_button.vue'; +import tooltip from '../../vue_shared/directives/tooltip'; - export default { - components: { - loadingIcon, - }, +export default { + components: { + Icon, + LoadingButton, + }, - directives: { - tooltip, - }, + directives: { + tooltip, + }, - props: { - stopUrl: { - type: String, - default: '', - }, + props: { + environment: { + type: Object, + required: true, }, + }, - data() { - return { - isLoading: false, - }; - }, + data() { + return { + isLoading: false, + }; + }, - computed: { - title() { - return 'Stop'; - }, + computed: { + title() { + return s__('Environments|Stop environment'); }, + }, - methods: { - onClick() { - // eslint-disable-next-line no-alert - if (window.confirm('Are you sure you want to stop this environment?')) { - this.isLoading = true; + mounted() { + eventHub.$on('stopEnvironment', this.onStopEnvironment); + }, - $(this.$el).tooltip('dispose'); + beforeDestroy() { + eventHub.$off('stopEnvironment', this.onStopEnvironment); + }, - eventHub.$emit('postAction', this.stopUrl); - } - }, + methods: { + onClick() { + $(this.$el).tooltip('dispose'); + eventHub.$emit('requestStopEnvironment', this.environment); + }, + onStopEnvironment(environment) { + if (this.environment.id === environment.id) { + this.isLoading = true; + } }, - }; + }, +}; </script> <template> - <button + <loading-button v-tooltip - :disabled="isLoading" + :loading="isLoading" :title="title" :aria-label="title" - type="button" - class="btn stop-env-link d-none d-sm-none d-md-block" + container-class="btn btn-danger d-none d-sm-none d-md-block" data-container="body" + data-toggle="modal" + data-target="#stop-environment-modal" @click="onClick" > - <i - class="fa fa-stop stop-env-icon" - aria-hidden="true" - > - </i> - <loading-icon v-if="isLoading" /> - </button> + <icon name="stop"/> + </loading-button> </template> diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue index f8e3165f8cd..350417e5ad0 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.vue +++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue @@ -1,31 +1,31 @@ <script> - /** - * Renders a terminal button to open a web terminal. - * Used in environments table. - */ - import Icon from '~/vue_shared/components/icon.vue'; - import tooltip from '../../vue_shared/directives/tooltip'; +/** + * Renders a terminal button to open a web terminal. + * Used in environments table. + */ +import Icon from '~/vue_shared/components/icon.vue'; +import tooltip from '../../vue_shared/directives/tooltip'; - export default { - components: { - Icon, +export default { + components: { + Icon, + }, + directives: { + tooltip, + }, + props: { + terminalPath: { + type: String, + required: false, + default: '', }, - directives: { - tooltip, + }, + computed: { + title() { + return 'Terminal'; }, - props: { - terminalPath: { - type: String, - required: false, - default: '', - }, - }, - computed: { - title() { - return 'Terminal'; - }, - }, - }; + }, +}; </script> <template> <a @@ -36,9 +36,6 @@ class="btn terminal-button d-none d-sm-none d-md-block" data-container="body" > - <icon - :size="12" - name="terminal" - /> + <icon name="terminal" /> </a> </template> diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index b18f02343d6..8efdfb8abe0 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -5,10 +5,12 @@ import eventHub from '../event_hub'; import environmentsMixin from '../mixins/environments_mixin'; import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; + import StopEnvironmentModal from './stop_environment_modal.vue'; export default { components: { emptyState, + StopEnvironmentModal, }, mixins: [ @@ -90,6 +92,8 @@ </script> <template> <div :class="cssContainerClass"> + <stop-environment-modal :environment="environmentInStopModal" /> + <div class="top-area"> <tabs :tabs="tabs" diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue new file mode 100644 index 00000000000..657cc8cd1aa --- /dev/null +++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue @@ -0,0 +1,92 @@ +<script> +import GlModal from '~/vue_shared/components/gl_modal.vue'; +import { s__, sprintf } from '~/locale'; +import tooltip from '~/vue_shared/directives/tooltip'; +import LoadingButton from '~/vue_shared/components/loading_button.vue'; +import eventHub from '../event_hub'; + +export default { + id: 'stop-environment-modal', + name: 'StopEnvironmentModal', + + components: { + GlModal, + LoadingButton, + }, + + directives: { + tooltip, + }, + + props: { + environment: { + type: Object, + required: true, + }, + }, + + computed: { + noStopActionMessage() { + return sprintf( + s__( + `Environments|Note that this action will stop the environment, + but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment + due to no “stop environment action” being defined + in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file.`, + ), + { + emphasisStart: '<strong>', + emphasisEnd: '</strong>', + ciConfigLinkStart: + '<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">', + ciConfigLinkEnd: '</a>', + }, + false, + ); + }, + }, + + methods: { + onSubmit() { + eventHub.$emit('stopEnvironment', this.environment); + }, + }, +}; +</script> + +<template> + <gl-modal + :id="$options.id" + :footer-primary-button-text="s__('Environments|Stop environment')" + footer-primary-button-variant="danger" + @submit="onSubmit" + > + <template slot="header"> + <h4 + class="modal-title d-flex mw-100" + > + Stopping + <span + v-tooltip + :title="environment.name" + class="text-truncate ml-1 mr-1 flex-fill" + >{{ environment.name }}</span> + ? + </h4> + </template> + + <p>{{ s__('Environments|Are you sure you want to stop this environment?') }}</p> + + <div + v-if="!environment.has_stop_action" + class="warning_message" + > + <p v-html="noStopActionMessage"></p> + <a + href="https://docs.gitlab.com/ee/ci/environments.html#stopping-an-environment" + target="_blank" + rel="noopener noreferrer" + >{{ s__('Environments|Learn more about stopping environments') }}</a> + </div> + </gl-modal> +</template> diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue index 5f72a39c5cb..e69bfa0b2cc 100644 --- a/app/assets/javascripts/environments/folder/environments_folder_view.vue +++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue @@ -1,12 +1,18 @@ <script> import environmentsMixin from '../mixins/environments_mixin'; import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; + import StopEnvironmentModal from '../components/stop_environment_modal.vue'; export default { + components: { + StopEnvironmentModal, + }, + mixins: [ environmentsMixin, CIPaginationMixin, ], + props: { endpoint: { type: String, @@ -38,6 +44,8 @@ </script> <template> <div :class="cssContainerClass"> + <stop-environment-modal :environment="environmentInStopModal" /> + <div v-if="!isLoading" class="top-area" diff --git a/app/assets/javascripts/environments/mixins/environments_mixin.js b/app/assets/javascripts/environments/mixins/environments_mixin.js index a7a79dbca70..d88624f7f8d 100644 --- a/app/assets/javascripts/environments/mixins/environments_mixin.js +++ b/app/assets/javascripts/environments/mixins/environments_mixin.js @@ -40,6 +40,7 @@ export default { scope: getParameterByName('scope') || 'available', page: getParameterByName('page') || '1', requestData: {}, + environmentInStopModal: {}, }; }, @@ -85,7 +86,7 @@ export default { Flash(s__('Environments|An error occurred while fetching the environments.')); }, - postAction(endpoint) { + postAction({ endpoint, errorMessage }) { if (!this.isMakingRequest) { this.isLoading = true; @@ -93,7 +94,7 @@ export default { .then(() => this.fetchEnvironments()) .catch(() => { this.isLoading = false; - Flash(s__('Environments|An error occurred while making the request.')); + Flash(errorMessage || s__('Environments|An error occurred while making the request.')); }); } }, @@ -106,6 +107,15 @@ export default { .catch(this.errorCallback); }, + updateStopModal(environment) { + this.environmentInStopModal = environment; + }, + + stopEnvironment(environment) { + const endpoint = environment.stop_path; + const errorMessage = s__('Environments|An error occurred while stopping the environment, please try again'); + this.postAction({ endpoint, errorMessage }); + }, }, computed: { @@ -162,9 +172,13 @@ export default { }); eventHub.$on('postAction', this.postAction); + eventHub.$on('requestStopEnvironment', this.updateStopModal); + eventHub.$on('stopEnvironment', this.stopEnvironment); }, - beforeDestroyed() { - eventHub.$off('postAction'); + beforeDestroy() { + eventHub.$off('postAction', this.postAction); + eventHub.$off('requestStopEnvironment', this.updateStopModal); + eventHub.$off('stopEnvironment', this.stopEnvironment); }, }; diff --git a/app/assets/javascripts/environments/services/environments_service.js b/app/assets/javascripts/environments/services/environments_service.js index 3b121551aca..4e07ccba91a 100644 --- a/app/assets/javascripts/environments/services/environments_service.js +++ b/app/assets/javascripts/environments/services/environments_service.js @@ -13,7 +13,7 @@ export default class EnvironmentsService { // eslint-disable-next-line class-methods-use-this postAction(endpoint) { - return axios.post(endpoint, {}, { emulateJSON: true }); + return axios.post(endpoint, {}); } getFolderContent(folderUrl) { diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue index 9f016e0338f..257a7432c20 100644 --- a/app/assets/javascripts/ide/components/ide.vue +++ b/app/assets/javascripts/ide/components/ide.vue @@ -1,6 +1,7 @@ <script> import Mousetrap from 'mousetrap'; import { mapActions, mapState, mapGetters } from 'vuex'; +import NewModal from './new_dropdown/modal.vue'; import IdeSidebar from './ide_side_bar.vue'; import RepoTabs from './repo_tabs.vue'; import IdeStatusBar from './ide_status_bar.vue'; @@ -13,6 +14,7 @@ const originalStopCallback = Mousetrap.stopCallback; export default { components: { + NewModal, IdeSidebar, RepoTabs, IdeStatusBar, @@ -137,5 +139,6 @@ export default { /> </div> <ide-status-bar :file="activeFile"/> + <new-modal /> </article> </template> diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue index 8fc4ebe6ca6..0a95c0bb30d 100644 --- a/app/assets/javascripts/ide/components/ide_tree.vue +++ b/app/assets/javascripts/ide/components/ide_tree.vue @@ -1,12 +1,16 @@ <script> import { mapState, mapGetters, mapActions } from 'vuex'; -import NewDropdown from './new_dropdown/index.vue'; +import Icon from '~/vue_shared/components/icon.vue'; import IdeTreeList from './ide_tree_list.vue'; +import Upload from './new_dropdown/upload.vue'; +import NewEntryButton from './new_dropdown/button.vue'; export default { components: { - NewDropdown, + Icon, + Upload, IdeTreeList, + NewEntryButton, }, computed: { ...mapState(['currentBranchId']), @@ -20,23 +24,42 @@ export default { } }, methods: { - ...mapActions(['updateViewer']), + ...mapActions(['updateViewer', 'openNewEntryModal', 'createTempEntry']), }, }; </script> <template> <ide-tree-list + header-class="d-flex w-100" viewer-type="editor" > <template slot="header" > {{ __('Edit') }} - <new-dropdown - :project-id="currentProject.name_with_namespace" - :branch="currentBranchId" - /> + <div class="ml-auto d-flex"> + <new-entry-button + :label="__('New file')" + :show-label="false" + class="d-flex border-0 p-0 mr-3" + icon="doc-new" + @click="openNewEntryModal({ type: 'blob' })" + /> + <upload + :show-label="false" + class="d-flex mr-3" + button-css-classes="border-0 p-0" + @create="createTempEntry" + /> + <new-entry-button + :label="__('New directory')" + :show-label="false" + class="d-flex border-0 p-0" + icon="folder-new" + @click="openNewEntryModal({ type: 'tree' })" + /> + </div> </template> </ide-tree-list> </template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/button.vue b/app/assets/javascripts/ide/components/new_dropdown/button.vue new file mode 100644 index 00000000000..7682b34ce4d --- /dev/null +++ b/app/assets/javascripts/ide/components/new_dropdown/button.vue @@ -0,0 +1,51 @@ +<script> +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + components: { + Icon, + }, + props: { + label: { + type: String, + required: false, + default: null, + }, + icon: { + type: String, + required: true, + }, + iconClasses: { + type: String, + required: false, + default: null, + }, + showLabel: { + type: Boolean, + required: false, + default: true, + }, + }, + methods: { + clicked() { + this.$emit('click'); + }, + }, +}; +</script> + +<template> + <button + :aria-label="label" + type="button" + @click.stop.prevent="clicked" + > + <icon + :name="icon" + :css-classes="iconClasses" + /> + <template v-if="showLabel"> + {{ label }} + </template> + </button> +</template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue index 1e398d7e1aa..c29e49ba766 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/index.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue @@ -3,12 +3,14 @@ import { mapActions } from 'vuex'; import icon from '~/vue_shared/components/icon.vue'; import newModal from './modal.vue'; import upload from './upload.vue'; +import ItemButton from './button.vue'; export default { components: { icon, newModal, upload, + ItemButton, }, props: { branch: { @@ -20,11 +22,13 @@ export default { required: false, default: '', }, + mouseOver: { + type: Boolean, + required: true, + }, }, data() { return { - openModal: false, - modalType: '', dropdownOpen: false, }; }, @@ -34,17 +38,18 @@ export default { this.$refs.dropdownMenu.scrollIntoView(); }); }, + mouseOver() { + if (!this.mouseOver) { + this.dropdownOpen = false; + } + }, }, methods: { - ...mapActions(['createTempEntry']), + ...mapActions(['createTempEntry', 'openNewEntryModal']), createNewItem(type) { - this.modalType = type; - this.openModal = true; + this.openNewEntryModal({ type, path: this.path }); this.dropdownOpen = false; }, - hideModal() { - this.openModal = false; - }, openDropdown() { this.dropdownOpen = !this.dropdownOpen; }, @@ -58,23 +63,19 @@ export default { :class="{ show: dropdownOpen, }" - class="dropdown" + class="dropdown d-flex" > <button + :aria-label="__('Create new file or directory')" type="button" - class="btn btn-sm btn-default dropdown-toggle add-to-tree" - aria-label="Create new file or directory" + class="rounded border-0 d-flex ide-entry-dropdown-toggle" @click.stop="openDropdown()" > <icon - :size="12" - name="plus" - css-classes="float-left" + name="hamburger" /> <icon - :size="12" name="arrow-down" - css-classes="float-left" /> </button> <ul @@ -82,39 +83,30 @@ export default { class="dropdown-menu dropdown-menu-right" > <li> - <a - href="#" - role="button" - @click.stop.prevent="createNewItem('blob')" - > - {{ __('New file') }} - </a> + <item-button + :label="__('New file')" + class="d-flex" + icon="doc-new" + icon-classes="mr-2" + @click="createNewItem('blob')" + /> </li> <li> <upload - :branch-id="branch" :path="path" @create="createTempEntry" /> </li> <li> - <a - href="#" - role="button" - @click.stop.prevent="createNewItem('tree')" - > - {{ __('New directory') }} - </a> + <item-button + :label="__('New directory')" + class="d-flex" + icon="folder-new" + icon-classes="mr-2" + @click="createNewItem('tree')" + /> </li> </ul> </div> - <new-modal - v-if="openModal" - :type="modalType" - :branch-id="branch" - :path="path" - @hide="hideModal" - @create="createTempEntry" - /> </div> </template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index 1e9668d5154..1867b7980d2 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -1,78 +1,70 @@ <script> import { __ } from '~/locale'; -import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue'; +import { mapActions, mapState } from 'vuex'; +import GlModal from '~/vue_shared/components/gl_modal.vue'; export default { components: { - DeprecatedModal, - }, - props: { - branchId: { - type: String, - required: true, - }, - type: { - type: String, - required: true, - }, - path: { - type: String, - required: true, - }, + GlModal, }, data() { return { - entryName: this.path !== '' ? `${this.path}/` : '', + name: '', }; }, computed: { + ...mapState(['newEntryModal']), + entryName: { + get() { + return this.name || (this.newEntryModal.path !== '' ? `${this.newEntryModal.path}/` : ''); + }, + set(val) { + this.name = val; + }, + }, modalTitle() { - if (this.type === 'tree') { + if (this.newEntryModal.type === 'tree') { return __('Create new directory'); } return __('Create new file'); }, buttonLabel() { - if (this.type === 'tree') { + if (this.newEntryModal.type === 'tree') { return __('Create directory'); } return __('Create file'); }, }, - mounted() { - this.$refs.fieldName.focus(); - }, methods: { + ...mapActions(['createTempEntry']), createEntryInStore() { - this.$emit('create', { - branchId: this.branchId, - name: this.entryName, - type: this.type, + this.createTempEntry({ + name: this.name, + type: this.newEntryModal.type, }); - - this.hideModal(); }, - hideModal() { - this.$emit('hide'); + focusInput() { + setTimeout(() => { + this.$refs.fieldName.focus(); + }); }, }, }; </script> <template> - <deprecated-modal - :title="modalTitle" - :primary-button-label="buttonLabel" - kind="success" - @cancel="hideModal" + <gl-modal + id="ide-new-entry" + :header-title-text="modalTitle" + :footer-primary-button-text="buttonLabel" + footer-primary-button-variant="success" @submit="createEntryInStore" + @open="focusInput" > - <form - slot="body" + <div class="form-group row" - @submit.prevent="createEntryInStore" > <label class="label-light col-form-label col-sm-3"> {{ __('Name') }} @@ -85,6 +77,6 @@ export default { class="form-control" /> </div> - </form> - </deprecated-modal> + </div> + </gl-modal> </template> diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue index 677b282bd61..5b1743bb30e 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue @@ -1,71 +1,85 @@ <script> - export default { - props: { - branchId: { - type: String, - required: true, - }, - path: { - type: String, - required: false, - default: '', - }, +import Icon from '~/vue_shared/components/icon.vue'; +import ItemButton from './button.vue'; + +export default { + components: { + Icon, + ItemButton, + }, + props: { + path: { + type: String, + required: false, + default: '', }, - mounted() { - this.$refs.fileUpload.addEventListener('change', this.openFile); + showLabel: { + type: Boolean, + required: false, + default: true, }, - beforeDestroy() { - this.$refs.fileUpload.removeEventListener('change', this.openFile); + buttonCssClasses: { + type: String, + required: false, + default: null, }, - methods: { - createFile(target, file, isText) { - const { name } = file; - let { result } = target; + }, + mounted() { + this.$refs.fileUpload.addEventListener('change', this.openFile); + }, + beforeDestroy() { + this.$refs.fileUpload.removeEventListener('change', this.openFile); + }, + methods: { + createFile(target, file, isText) { + const { name } = file; + let { result } = target; - if (!isText) { - // eslint-disable-next-line prefer-destructuring - result = result.split('base64,')[1]; - } + if (!isText) { + // eslint-disable-next-line prefer-destructuring + result = result.split('base64,')[1]; + } - this.$emit('create', { - name: `${(this.path ? `${this.path}/` : '')}${name}`, - branchId: this.branchId, - type: 'blob', - content: result, - base64: !isText, - }); - }, - readFile(file) { - const reader = new FileReader(); - const isText = file.type.match(/text.*/) !== null; + this.$emit('create', { + name: `${this.path ? `${this.path}/` : ''}${name}`, + type: 'blob', + content: result, + base64: !isText, + }); + }, + readFile(file) { + const reader = new FileReader(); + const isText = file.type.match(/text.*/) !== null; - reader.addEventListener('load', e => this.createFile(e.target, file, isText), { once: true }); + reader.addEventListener('load', e => this.createFile(e.target, file, isText), { once: true }); - if (isText) { - reader.readAsText(file); - } else { - reader.readAsDataURL(file); - } - }, - openFile() { - Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file)); - }, - startFileUpload() { - this.$refs.fileUpload.click(); - }, + if (isText) { + reader.readAsText(file); + } else { + reader.readAsDataURL(file); + } + }, + openFile() { + Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file)); }, - }; + startFileUpload() { + this.$refs.fileUpload.click(); + }, + }, +}; </script> <template> <div> - <a - href="#" - role="button" - @click.stop.prevent="startFileUpload" - > - {{ __('Upload file') }} - </a> + <item-button + :class="buttonCssClasses" + :show-label="showLabel" + :icon-classes="showLabel ? 'mr-2' : ''" + :label="__('Upload file')" + class="d-flex" + icon="upload" + @click="startFileUpload" + /> <input id="file-upload" ref="fileUpload" diff --git a/app/assets/javascripts/ide/components/repo_file.vue b/app/assets/javascripts/ide/components/repo_file.vue index f490a3a2a39..3b4dd5ae9aa 100644 --- a/app/assets/javascripts/ide/components/repo_file.vue +++ b/app/assets/javascripts/ide/components/repo_file.vue @@ -40,6 +40,11 @@ export default { default: false, }, }, + data() { + return { + mouseOver: false, + }; + }, computed: { ...mapGetters([ 'getChangesInFolder', @@ -142,6 +147,9 @@ export default { hasUrlAtCurrentRoute() { return this.$router.currentRoute.path === `/project${this.file.url}`; }, + toggleHover(over) { + this.mouseOver = over; + }, }, }; </script> @@ -153,6 +161,8 @@ export default { class="file" role="button" @click="clickFile" + @mouseover="toggleHover(true)" + @mouseout="toggleHover(false)" > <div class="file-name" @@ -206,6 +216,7 @@ export default { :project-id="file.projectId" :branch="file.branchId" :path="file.path" + :mouse-over="mouseOver" class="float-right prepend-left-8" /> </div> diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index 5e91fa915ff..b5bd6f5a6bb 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -52,7 +52,7 @@ export const setResizingStatus = ({ commit }, resizing) => { export const createTempEntry = ( { state, commit, dispatch }, - { branchId, name, type, content = '', base64 = false }, + { name, type, content = '', base64 = false }, ) => new Promise(resolve => { const worker = new FilesDecoratorWorker(); @@ -81,7 +81,7 @@ export const createTempEntry = ( commit(types.CREATE_TMP_ENTRY, { data, projectId: state.currentProjectId, - branchId, + branchId: state.currentBranchId, }); if (type === 'blob') { @@ -100,7 +100,7 @@ export const createTempEntry = ( worker.postMessage({ data: [fullName], projectId: state.currentProjectId, - branchId, + branchId: state.currentBranchId, type, tempFile: true, base64, @@ -178,6 +178,13 @@ export const setLinks = ({ commit }, links) => commit(types.SET_LINKS, links); export const setErrorMessage = ({ commit }, errorMessage) => commit(types.SET_ERROR_MESSAGE, errorMessage); +export const openNewEntryModal = ({ commit }, { type, path = '' }) => { + commit(types.OPEN_NEW_ENTRY_MODAL, { type, path }); + + // open the modal manually so we don't mess around with dropdown/rows + $('#ide-new-entry').modal('show'); +}; + export * from './actions/tree'; export * from './actions/file'; export * from './actions/project'; diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 555802e1811..8d6f9ccaf34 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -74,3 +74,5 @@ export const CLEAR_PROJECTS = 'CLEAR_PROJECTS'; export const RESET_OPEN_FILES = 'RESET_OPEN_FILES'; export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE'; + +export const OPEN_NEW_ENTRY_MODAL = 'OPEN_NEW_ENTRY_MODAL'; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 702be2140e2..f8091f5b5e0 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -166,6 +166,11 @@ export default { [types.SET_ERROR_MESSAGE](state, errorMessage) { Object.assign(state, { errorMessage }); }, + [types.OPEN_NEW_ENTRY_MODAL](state, { type, path }) { + Object.assign(state, { + newEntryModal: { type, path }, + }); + }, ...projectMutations, ...mergeRequestMutation, ...fileMutations, diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index be229b2c723..0f32a267469 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -26,4 +26,8 @@ export default () => ({ rightPane: null, links: {}, errorMessage: null, + newEntryModal: { + type: '', + path: '', + }, }); diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 963e3a37b39..26482a02e00 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -200,7 +200,7 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea" class="btn btn-cancel note-edit-cancel js-close-discussion-note-form" type="button" @click="cancelHandler()"> - {{ __('Discard draft') }} + Cancel </button> </div> </form> diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index b2bf86eea56..3eefbe11c37 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -15,6 +15,8 @@ let eTagPoll; export const expandDiscussion = ({ commit }, data) => commit(types.EXPAND_DISCUSSION, data); +export const collapseDiscussion = ({ commit }, data) => commit(types.COLLAPSE_DISCUSSION, data); + export const setNotesData = ({ commit }, data) => commit(types.SET_NOTES_DATA, data); export const setNoteableData = ({ commit }, data) => commit(types.SET_NOTEABLE_DATA, data); diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js index a25098fbc06..6f374f78691 100644 --- a/app/assets/javascripts/notes/stores/mutation_types.js +++ b/app/assets/javascripts/notes/stores/mutation_types.js @@ -1,7 +1,6 @@ export const ADD_NEW_NOTE = 'ADD_NEW_NOTE'; export const ADD_NEW_REPLY_TO_DISCUSSION = 'ADD_NEW_REPLY_TO_DISCUSSION'; export const DELETE_NOTE = 'DELETE_NOTE'; -export const EXPAND_DISCUSSION = 'EXPAND_DISCUSSION'; export const REMOVE_PLACEHOLDER_NOTES = 'REMOVE_PLACEHOLDER_NOTES'; export const SET_NOTES_DATA = 'SET_NOTES_DATA'; export const SET_NOTEABLE_DATA = 'SET_NOTEABLE_DATA'; @@ -11,12 +10,16 @@ export const SET_LAST_FETCHED_AT = 'SET_LAST_FETCHED_AT'; export const SET_TARGET_NOTE_HASH = 'SET_TARGET_NOTE_HASH'; export const SHOW_PLACEHOLDER_NOTE = 'SHOW_PLACEHOLDER_NOTE'; export const TOGGLE_AWARD = 'TOGGLE_AWARD'; -export const TOGGLE_DISCUSSION = 'TOGGLE_DISCUSSION'; export const UPDATE_NOTE = 'UPDATE_NOTE'; export const UPDATE_DISCUSSION = 'UPDATE_DISCUSSION'; export const SET_DISCUSSION_DIFF_LINES = 'SET_DISCUSSION_DIFF_LINES'; export const SET_NOTES_FETCHED_STATE = 'SET_NOTES_FETCHED_STATE'; +// DISCUSSION +export const COLLAPSE_DISCUSSION = 'COLLAPSE_DISCUSSION'; +export const EXPAND_DISCUSSION = 'EXPAND_DISCUSSION'; +export const TOGGLE_DISCUSSION = 'TOGGLE_DISCUSSION'; + // Issue export const CLOSE_ISSUE = 'CLOSE_ISSUE'; export const REOPEN_ISSUE = 'REOPEN_ISSUE'; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index a1849269010..ab6a95e2601 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -58,6 +58,11 @@ export default { discussion.expanded = true; }, + [types.COLLAPSE_DISCUSSION](state, { discussionId }) { + const discussion = utils.findNoteObjectById(state.discussions, discussionId); + discussion.expanded = false; + }, + [types.REMOVE_PLACEHOLDER_NOTES](state) { const { discussions } = state; diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js index 9aa83ce6269..ff19b9a9c30 100644 --- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js +++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js @@ -39,7 +39,6 @@ export default class Todos { } initFilters() { - this.initFilterDropdown($('.js-group-search'), 'group_id', ['text']); this.initFilterDropdown($('.js-project-search'), 'project_id', ['text']); this.initFilterDropdown($('.js-type-search'), 'type'); this.initFilterDropdown($('.js-action-search'), 'action_id'); @@ -54,16 +53,7 @@ export default class Todos { filterable: searchFields ? true : false, search: { fields: searchFields }, data: $dropdown.data('data'), - clicked: () => { - const $formEl = $dropdown.closest('form.filter-form'); - const mutexDropdowns = { - group_id: 'project_id', - project_id: 'group_id', - }; - - $formEl.find(`input[name="${mutexDropdowns[fieldName]}"]`).remove(); - $formEl.submit(); - }, + clicked: () => $dropdown.closest('form.filter-form').submit(), }); } diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue deleted file mode 100644 index ffaed9c7193..00000000000 --- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue +++ /dev/null @@ -1,98 +0,0 @@ -<script> -import { __ } from '~/locale'; -import tooltip from '~/vue_shared/directives/tooltip'; - -import Icon from '~/vue_shared/components/icon.vue'; -import LoadingIcon from '~/vue_shared/components/loading_icon.vue'; - -const MARK_TEXT = __('Mark todo as done'); -const TODO_TEXT = __('Add todo'); - -export default { - directives: { - tooltip, - }, - components: { - Icon, - LoadingIcon, - }, - props: { - issuableId: { - type: Number, - required: true, - }, - issuableType: { - type: String, - required: true, - }, - isTodo: { - type: Boolean, - required: false, - default: true, - }, - isActionActive: { - type: Boolean, - required: false, - default: false, - }, - collapsed: { - type: Boolean, - required: false, - default: false, - }, - }, - computed: { - buttonClasses() { - return this.collapsed ? - 'btn-blank btn-todo sidebar-collapsed-icon dont-change-state' : - 'btn btn-default btn-todo issuable-header-btn float-right'; - }, - buttonLabel() { - return this.isTodo ? MARK_TEXT : TODO_TEXT; - }, - collapsedButtonIconClasses() { - return this.isTodo ? 'todo-undone' : ''; - }, - collapsedButtonIcon() { - return this.isTodo ? 'todo-done' : 'todo-add'; - }, - }, - methods: { - handleButtonClick() { - this.$emit('toggleTodo'); - }, - }, -}; -</script> - -<template> - <button - v-tooltip - :class="buttonClasses" - :title="buttonLabel" - :aria-label="buttonLabel" - :data-issuable-id="issuableId" - :data-issuable-type="issuableType" - type="button" - data-container="body" - data-placement="left" - data-boundary="viewport" - @click="handleButtonClick" - > - <icon - v-show="collapsed" - :css-classes="collapsedButtonIconClasses" - :name="collapsedButtonIcon" - /> - <span - v-show="!collapsed" - class="issuable-todo-inner" - > - {{ buttonLabel }} - </span> - <loading-icon - v-show="isActionActive" - :inline="true" - /> - </button> -</template> diff --git a/app/assets/javascripts/vue_shared/components/gl_modal.vue b/app/assets/javascripts/vue_shared/components/gl_modal.vue index b298b989203..416eda796a7 100644 --- a/app/assets/javascripts/vue_shared/components/gl_modal.vue +++ b/app/assets/javascripts/vue_shared/components/gl_modal.vue @@ -45,6 +45,11 @@ export default { emitSubmit(event) { this.$emit('submit', event); }, + opened({ propertyName }) { + if (propertyName === 'opacity') { + this.$emit('open'); + } + }, }, }; </script> @@ -55,6 +60,7 @@ export default { class="modal fade" tabindex="-1" role="dialog" + @transitionend="opened" > <div :class="modalSizeClass" diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue index 80dc7d3557c..ac2e99abe77 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue @@ -12,11 +12,6 @@ export default { type: Boolean, required: true, }, - cssClasses: { - type: String, - required: false, - default: '', - }, }, computed: { tooltipLabel() { @@ -35,12 +30,10 @@ export default { <button v-tooltip :title="tooltipLabel" - :class="cssClasses" type="button" class="btn btn-blank gutter-toggle btn-sidebar-action" data-container="body" data-placement="left" - data-boundary="viewport" @click="toggle" > <i diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 199039f38f7..3144dcc4dc0 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -23,7 +23,7 @@ } .btn-group { - > a { + > .btn:not(.btn-danger) { color: $gl-text-color-secondary; } diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index f6617380cc0..f9fd9f1ab8b 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -449,7 +449,6 @@ .todo-undone { color: $gl-link-color; - fill: $gl-link-color; } .author { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index c32049e1b33..2af79c511ba 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -116,10 +116,8 @@ .modify-merge-commit-link { padding: 0; - background-color: transparent; border: 0; - color: $gl-text-color; &:hover, @@ -501,10 +499,6 @@ } } -.merge-request-details .content-block { - border-bottom: 0; -} - .mr-source-target { display: flex; flex-wrap: wrap; diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 6e2b285285a..8b1227b9131 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -44,6 +44,7 @@ padding-bottom: $grid-size; .file { + height: 32px; cursor: pointer; &.file-active { @@ -716,32 +717,6 @@ justify-content: center; } -.ide-new-btn { - .btn { - padding-top: 3px; - padding-bottom: 3px; - } - - .dropdown { - display: flex; - } - - .dropdown-toggle svg { - top: 0; - } - - .dropdown-menu { - left: auto; - right: 0; - - label { - font-weight: $gl-font-weight-normal; - padding: 5px 8px; - margin-bottom: 0; - } - } -} - .ide { overflow: hidden; @@ -1340,3 +1315,24 @@ overflow: auto; } } + +.ide-entry-dropdown-toggle { + padding: $gl-padding-4; + background-color: $theme-gray-100; + + &:hover { + background-color: $theme-gray-200; + } + + &:active, + &:focus { + color: $white-normal; + background-color: $blue-500; + outline: 0; + } +} + +.ide-new-btn .dropdown.show .ide-entry-dropdown-toggle { + color: $white-normal; + background-color: $blue-500; +} diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss index 010a2c05a1c..e5d7dd13915 100644 --- a/app/assets/stylesheets/pages/todos.scss +++ b/app/assets/stylesheets/pages/todos.scss @@ -174,18 +174,6 @@ } } -@include media-breakpoint-down(lg) { - .todos-filters { - .filter-categories { - width: 75%; - - .filter-item { - margin-bottom: 10px; - } - } - } -} - @include media-breakpoint-down(xs) { .todo { .avatar { @@ -211,10 +199,6 @@ } .todos-filters { - .filter-categories { - width: auto; - } - .dropdown-menu-toggle { width: 100%; } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f864fbcaa43..5194bdb6105 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -30,7 +30,14 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception, prepend: true helper_method :can? - helper_method :import_sources_enabled?, :github_import_enabled?, :gitea_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled?, :bitbucket_server_import_enabled? + helper_method :import_sources_enabled?, :github_import_enabled?, + :gitea_import_enabled?, :github_import_configured?, + :gitlab_import_enabled?, :gitlab_import_configured?, + :bitbucket_import_enabled?, :bitbucket_import_configured?, + :bitbucket_server_import_enabled?, + :google_code_import_enabled?, :fogbugz_import_enabled?, + :git_import_enabled?, :gitlab_project_import_enabled?, + :manifest_import_enabled? rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) @@ -355,6 +362,10 @@ class ApplicationController < ActionController::Base Gitlab::CurrentSettings.import_sources.include?('gitlab_project') end + def manifest_import_enabled? + Group.supports_nested_groups? && Gitlab::CurrentSettings.import_sources.include?('manifest') + end + # U2F (universal 2nd factor) devices need a unique identifier for the application # to perform authentication. # https://developers.yubico.com/U2F/App_ID.html diff --git a/app/controllers/concerns/todos_actions.rb b/app/controllers/concerns/todos_actions.rb deleted file mode 100644 index c0acdb3498d..00000000000 --- a/app/controllers/concerns/todos_actions.rb +++ /dev/null @@ -1,12 +0,0 @@ -module TodosActions - extend ActiveSupport::Concern - - def create - todo = TodoService.new.mark_todo(issuable, current_user) - - render json: { - count: TodosFinder.new(current_user, state: :pending).execute.count, - delete_path: dashboard_todo_path(todo) - } - end -end diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb index bd7111e28bc..f9e8fe624e8 100644 --- a/app/controllers/dashboard/todos_controller.rb +++ b/app/controllers/dashboard/todos_controller.rb @@ -70,7 +70,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController end def todo_params - params.permit(:action_id, :author_id, :project_id, :type, :sort, :state, :group_id) + params.permit(:action_id, :author_id, :project_id, :type, :sort, :state) end def redirect_out_of_range(todos) diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb new file mode 100644 index 00000000000..e5a719fa0df --- /dev/null +++ b/app/controllers/import/manifest_controller.rb @@ -0,0 +1,93 @@ +class Import::ManifestController < Import::BaseController + before_action :whitelist_query_limiting, only: [:create] + before_action :verify_import_enabled + before_action :ensure_import_vars, only: [:create, :status] + + def new + end + + def status + @already_added_projects = find_already_added_projects + already_added_import_urls = @already_added_projects.pluck(:import_url) + + @pending_repositories = repositories.to_a.reject do |repository| + already_added_import_urls.include?(repository[:url]) + end + end + + def upload + group = Group.find(params[:group_id]) + + unless can?(current_user, :create_projects, group) + @errors = ["You don't have enough permissions to create projects in the selected group"] + + render :new && return + end + + manifest = Gitlab::ManifestImport::Manifest.new(params[:manifest].tempfile) + + if manifest.valid? + session[:manifest_import_repositories] = manifest.projects + session[:manifest_import_group_id] = group.id + + redirect_to status_import_manifest_path + else + @errors = manifest.errors + + render :new + end + end + + def jobs + render json: find_jobs + end + + def create + repository = repositories.find do |project| + project[:id] == params[:repo_id].to_i + end + + project = Gitlab::ManifestImport::ProjectCreator.new(repository, group, current_user).execute + + if project.persisted? + render json: ProjectSerializer.new.represent(project) + else + render json: { errors: project_save_error(project) }, status: :unprocessable_entity + end + end + + private + + def ensure_import_vars + unless group && repositories.present? + redirect_to(new_import_manifest_path) + end + end + + def group + @group ||= Group.find_by(id: session[:manifest_import_group_id]) + end + + def repositories + @repositories ||= session[:manifest_import_repositories] + end + + def find_jobs + find_already_added_projects.to_json(only: [:id], methods: [:import_status]) + end + + def find_already_added_projects + group.all_projects + .where(import_type: 'manifest') + .where(creator_id: current_user) + .includes(:import_state) + end + + def verify_import_enabled + render_404 unless manifest_import_enabled? + end + + def whitelist_query_limiting + Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/48939') + end +end diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb index 395c5336ad5..68353e6a210 100644 --- a/app/controllers/projects/environments_controller.rb +++ b/app/controllers/projects/environments_controller.rb @@ -2,7 +2,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController layout 'project' before_action :authorize_read_environment! before_action :authorize_create_environment!, only: [:new, :create] - before_action :authorize_create_deployment!, only: [:stop] + before_action :authorize_stop_environment!, only: [:stop] before_action :authorize_update_environment!, only: [:edit, :update] before_action :authorize_admin_environment!, only: [:terminal, :terminal_websocket_authorize] before_action :environment, only: [:show, :edit, :update, :stop, :terminal, :terminal_websocket_authorize, :metrics] @@ -175,4 +175,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController def environment @environment ||= project.environments.find(params[:id]) end + + def authorize_stop_environment! + access_denied! unless can?(current_user, :stop_environment, environment) + end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 1ad2e93c85f..dc6551fc761 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -192,7 +192,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo deployment = environment.first_deployment_for(@merge_request.diff_head_sha) stop_url = - if environment.stop_action? && can?(current_user, :create_deployment, environment) + if can?(current_user, :stop_environment, environment) stop_project_environment_path(project, environment) end diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb index 93fb9da6510..a41fcb85c40 100644 --- a/app/controllers/projects/todos_controller.rb +++ b/app/controllers/projects/todos_controller.rb @@ -1,13 +1,19 @@ class Projects::TodosController < Projects::ApplicationController - include Gitlab::Utils::StrongMemoize - include TodosActions - before_action :authenticate_user!, only: [:create] + def create + todo = TodoService.new.mark_todo(issuable, current_user) + + render json: { + count: TodosFinder.new(current_user, state: :pending).execute.count, + delete_path: dashboard_todo_path(todo) + } + end + private def issuable - strong_memoize(:issuable) do + @issuable ||= begin case params[:issuable_type] when "issue" IssuesFinder.new(current_user, project_id: @project.id).find(params[:issuable_id]) diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index 2156413fb26..09e2c586f2a 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -15,7 +15,6 @@ class TodosFinder prepend FinderWithCrossProjectAccess include FinderMethods - include Gitlab::Utils::StrongMemoize requires_cross_project_access unless: -> { project? } @@ -35,11 +34,9 @@ class TodosFinder items = by_author(items) items = by_state(items) items = by_type(items) - items = by_group(items) # Filtering by project HAS TO be the last because we use # the project IDs yielded by the todos query thus far items = by_project(items) - items = visible_to_user(items) sort(items) end @@ -85,10 +82,6 @@ class TodosFinder params[:project_id].present? end - def group? - params[:group_id].present? - end - def project return @project if defined?(@project) @@ -107,14 +100,18 @@ class TodosFinder @project end - def group - strong_memoize(:group) do - Group.find(params[:group_id]) + def project_ids(items) + ids = items.except(:order).select(:project_id) + if Gitlab::Database.mysql? + # To make UPDATE work on MySQL, wrap it in a SELECT with an alias + ids = Todo.except(:order).select('*').from("(#{ids.to_sql}) AS t") end + + ids end def type? - type.present? && %w(Issue MergeRequest Epic).include?(type) + type.present? && %w(Issue MergeRequest).include?(type) end def type @@ -151,37 +148,12 @@ class TodosFinder def by_project(items) if project? - items = items.where(project: project) - end - - items - end + items.where(project: project) + else + projects = Project.public_or_visible_to_user(current_user) - def by_group(items) - if group? - groups = group.self_and_descendants - items = items.where( - 'project_id IN (?) OR group_id IN (?)', - Project.where(group: groups).select(:id), - groups.select(:id) - ) + items.joins(:project).merge(projects) end - - items - end - - def visible_to_user(items) - projects = Project.public_or_visible_to_user(current_user) - groups = Group.public_or_visible_to_user(current_user) - - items - .joins('LEFT JOIN namespaces ON namespaces.id = todos.group_id') - .joins('LEFT JOIN projects ON projects.id = todos.project_id') - .where( - 'project_id IN (?) OR group_id IN (?)', - projects.select(:id), - groups.select(:id) - ) end def by_state(items) diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index ef1bf283d0c..358b896702b 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -251,6 +251,7 @@ module ApplicationSettingsHelper :user_oauth_applications, :version_check_enabled, :allow_local_requests_from_hooks_and_services, + :hide_third_party_offers, :enforce_terms, :terms, :mirror_available diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index c24d340d184..8fd0b6f14c6 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -4,6 +4,7 @@ module ClustersHelper end def render_gcp_signup_offer + return if Gitlab::CurrentSettings.current_application_settings.hide_third_party_offers? return unless show_gcp_signup_offer? content_tag :section, class: 'no-animate expanded' do diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 7bbdc798ddd..8766bb43cac 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -131,19 +131,6 @@ module IssuablesHelper end end - def group_dropdown_label(group_id, default_label) - return default_label if group_id.nil? - return "Any group" if group_id == "0" - - group = ::Group.find_by(id: group_id) - - if group - group.full_name - else - default_label - end - end - def milestone_dropdown_label(milestone_title, default_label = "Milestone") title = case milestone_title diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index 9be93fa69ae..9008db1b300 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -3,7 +3,7 @@ module NamespacesHelper params.dig(:project, :namespace_id) || params[:namespace_id] end - def namespaces_options(selected = :current_user, display_path: false, extra_group: nil) + def namespaces_options(selected = :current_user, display_path: false, extra_group: nil, groups_only: false) groups = current_user.manageable_groups .joins(:route) .includes(:route) @@ -20,10 +20,13 @@ module NamespacesHelper options = [] options << options_for_group(groups, display_path: display_path, type: 'group') - options << options_for_group(users, display_path: display_path, type: 'user') - if selected == :current_user && current_user.namespace - selected = current_user.namespace.id + unless groups_only + options << options_for_group(users, display_path: display_path, type: 'user') + + if selected == :current_user && current_user.namespace + selected = current_user.namespace.id + end end grouped_options_for_select(options, selected) diff --git a/app/helpers/pipeline_schedules_helper.rb b/app/helpers/pipeline_schedules_helper.rb index 6edaf78de1b..4b9f6bd2caf 100644 --- a/app/helpers/pipeline_schedules_helper.rb +++ b/app/helpers/pipeline_schedules_helper.rb @@ -3,7 +3,7 @@ module PipelineSchedulesHelper ActiveSupport::TimeZone.all.map do |timezone| { name: timezone.name, - offset: timezone.utc_offset, + offset: timezone.now.utc_offset, identifier: timezone.tzinfo.identifier } end diff --git a/app/helpers/time_helper.rb b/app/helpers/time_helper.rb index 271e839692a..336385f6798 100644 --- a/app/helpers/time_helper.rb +++ b/app/helpers/time_helper.rb @@ -5,9 +5,13 @@ module TimeHelper seconds = interval_in_seconds - minutes * 60 if minutes >= 1 - "#{pluralize(minutes, "minute")} #{pluralize(seconds, "second")}" + if seconds % 60 == 0 + pluralize(minutes, "minute") + else + [pluralize(minutes, "minute"), pluralize(seconds, "second")].to_sentence + end else - "#{pluralize(seconds, "second")}" + pluralize(seconds, "second") end end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 7cd74358168..f7620e0b6b8 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -43,7 +43,7 @@ module TodosHelper project_commit_path(todo.project, todo.target, anchor: anchor) else - path = [todo.parent, todo.target] + path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target] path.unshift(:pipelines) if todo.build_failed? @@ -167,12 +167,4 @@ module TodosHelper def show_todo_state?(todo) (todo.target.is_a?(MergeRequest) || todo.target.is_a?(Issue)) && %w(closed merged).include?(todo.target.state) end - - def todo_group_options - groups = current_user.authorized_groups.map do |group| - { id: group.id, text: group.full_name } - end - - groups.unshift({ id: '', text: 'Any Group' }).to_json - end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index bddeb8b0352..f770b219422 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -294,6 +294,7 @@ class ApplicationSetting < ActiveRecord::Base gitaly_timeout_medium: 30, gitaly_timeout_default: 55, allow_local_requests_from_hooks_and_services: false, + hide_third_party_offers: false, mirror_available: true } end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 44103e3bc4f..d8ddb4bc667 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -437,9 +437,9 @@ module Ci end def artifacts_metadata_entry(path, **options) - artifacts_metadata.use_file do |metadata_path| + artifacts_metadata.open do |metadata_stream| metadata = Gitlab::Ci::Build::Artifacts::Metadata.new( - metadata_path, + metadata_stream, path, **options) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 7a459078151..b93c1145f82 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -243,12 +243,6 @@ module Issuable opened? end - def overdue? - return false unless respond_to?(:due_date) - - due_date.try(:past?) || false - end - def user_notes_count if notes.loaded? # Use the in-memory association to select and count to avoid hitting the db diff --git a/app/models/concerns/protected_ref_access.rb b/app/models/concerns/protected_ref_access.rb index e3a7f2d5498..71b0c3468b9 100644 --- a/app/models/concerns/protected_ref_access.rb +++ b/app/models/concerns/protected_ref_access.rb @@ -2,19 +2,20 @@ module ProtectedRefAccess extend ActiveSupport::Concern ALLOWED_ACCESS_LEVELS = [ - Gitlab::Access::MASTER, + Gitlab::Access::MAINTAINER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS ].freeze HUMAN_ACCESS_LEVELS = { - Gitlab::Access::MASTER => "Maintainers".freeze, + Gitlab::Access::MAINTAINER => "Maintainers".freeze, Gitlab::Access::DEVELOPER => "Developers + Maintainers".freeze, Gitlab::Access::NO_ACCESS => "No one".freeze }.freeze included do - scope :master, -> { where(access_level: Gitlab::Access::MASTER) } + scope :master, -> { maintainer } # @deprecated + scope :maintainer, -> { where(access_level: Gitlab::Access::MAINTAINER) } scope :developer, -> { where(access_level: Gitlab::Access::DEVELOPER) } validates :access_level, presence: true, if: :role?, inclusion: { diff --git a/app/models/concerns/select_for_project_authorization.rb b/app/models/concerns/select_for_project_authorization.rb index 58194b0ea13..7af0fdbd618 100644 --- a/app/models/concerns/select_for_project_authorization.rb +++ b/app/models/concerns/select_for_project_authorization.rb @@ -6,8 +6,11 @@ module SelectForProjectAuthorization select("projects.id AS project_id, members.access_level") end - def select_as_master_for_project_authorization - select(["projects.id AS project_id", "#{Gitlab::Access::MASTER} AS access_level"]) + def select_as_maintainer_for_project_authorization + select(["projects.id AS project_id", "#{Gitlab::Access::MAINTAINER} AS access_level"]) end + + # @deprecated + alias_method :select_as_master_for_project_authorization, :select_as_maintainer_for_project_authorization end end diff --git a/app/models/group.rb b/app/models/group.rb index b0392774379..ddebaff50b0 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -39,8 +39,6 @@ class Group < Namespace has_many :boards has_many :badges, class_name: 'GroupBadge' - has_many :todos - accepts_nested_attributes_for :variables, allow_destroy: true validate :visibility_level_allowed_by_projects @@ -84,12 +82,6 @@ class Group < Namespace where(id: user.authorized_groups.select(:id).reorder(nil)) end - def public_or_visible_to_user(user) - where('id IN (?) OR namespaces.visibility_level IN (?)', - user.authorized_groups.select(:id), - Gitlab::VisibilityLevel.levels_for_user(user)) - end - def select_for_project_authorization if current_scope.joins_values.include?(:shared_projects) joins('INNER JOIN namespaces project_namespace ON project_namespace.id = projects.namespace_id') @@ -186,10 +178,13 @@ class Group < Namespace add_user(user, :developer, current_user: current_user) end - def add_master(user, current_user = nil) - add_user(user, :master, current_user: current_user) + def add_maintainer(user, current_user = nil) + add_user(user, :maintainer, current_user: current_user) end + # @deprecated + alias_method :add_master, :add_maintainer + def add_owner(user, current_user = nil) add_user(user, :owner, current_user: current_user) end @@ -206,12 +201,15 @@ class Group < Namespace members_with_parents.owners.where(user_id: user).any? end - def has_master?(user) + def has_maintainer?(user) return false unless user - members_with_parents.masters.where(user_id: user).any? + members_with_parents.maintainers.where(user_id: user).any? end + # @deprecated + alias_method :has_master?, :has_maintainer? + # Check if user is a last owner of the group. # Parent owners are ignored for nested groups. def last_owner?(user) diff --git a/app/models/issue.rb b/app/models/issue.rb index 983684a5e05..4715d942c8d 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -275,6 +275,10 @@ class Issue < ActiveRecord::Base user ? readable_by?(user) : publicly_visible? end + def overdue? + due_date.try(:past?) || false + end + def check_for_spam? project.public? && (title_changed? || description_changed?) end diff --git a/app/models/member.rb b/app/models/member.rb index 68572f2e33a..00a13a279a9 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -69,9 +69,11 @@ class Member < ActiveRecord::Base scope :guests, -> { active.where(access_level: GUEST) } scope :reporters, -> { active.where(access_level: REPORTER) } scope :developers, -> { active.where(access_level: DEVELOPER) } - scope :masters, -> { active.where(access_level: MASTER) } + scope :maintainers, -> { active.where(access_level: MAINTAINER) } + scope :masters, -> { maintainers } # @deprecated scope :owners, -> { active.where(access_level: OWNER) } - scope :owners_and_masters, -> { active.where(access_level: [OWNER, MASTER]) } + scope :owners_and_maintainers, -> { active.where(access_level: [OWNER, MAINTAINER]) } + scope :owners_and_masters, -> { owners_and_maintainers } # @deprecated scope :order_name_asc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'ASC')) } scope :order_name_desc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'DESC')) } diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 024106056b4..4f27d0aeaf8 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -17,19 +17,19 @@ class ProjectMember < Member # Add users to projects with passed access option # # access can be an integer representing a access code - # or symbol like :master representing role + # or symbol like :maintainer representing role # # Ex. # add_users_to_projects( # project_ids, # user_ids, - # ProjectMember::MASTER + # ProjectMember::MAINTAINER # ) # # add_users_to_projects( # project_ids, # user_ids, - # :master + # :maintainer # ) # def add_users_to_projects(project_ids, users, access_level, current_user: nil, expires_at: nil) diff --git a/app/models/note.rb b/app/models/note.rb index 3918bbee194..abc40d9016e 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -229,10 +229,6 @@ class Note < ActiveRecord::Base !for_personal_snippet? end - def for_issuable? - for_issue? || for_merge_request? - end - def skip_project_check? !for_project_noteable? end diff --git a/app/models/project.rb b/app/models/project.rb index 770262f6193..1894de6ceed 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -269,7 +269,8 @@ class Project < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true delegate :members, to: :team, prefix: true delegate :add_user, :add_users, to: :team - delegate :add_guest, :add_reporter, :add_developer, :add_master, :add_role, to: :team + delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_role, to: :team + delegate :add_master, to: :team # @deprecated delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings # Validations @@ -1647,10 +1648,10 @@ class Project < ActiveRecord::Base params = { name: default_branch, push_access_levels_attributes: [{ - access_level: Gitlab::CurrentSettings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_PUSH ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER + access_level: Gitlab::CurrentSettings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_PUSH ? Gitlab::Access::DEVELOPER : Gitlab::Access::MAINTAINER }], merge_access_levels_attributes: [{ - access_level: Gitlab::CurrentSettings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE ? Gitlab::Access::DEVELOPER : Gitlab::Access::MASTER + access_level: Gitlab::CurrentSettings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE ? Gitlab::Access::DEVELOPER : Gitlab::Access::MAINTAINER }] } diff --git a/app/models/project_group_link.rb b/app/models/project_group_link.rb index ac1e9ab2b0b..cf8fc41e870 100644 --- a/app/models/project_group_link.rb +++ b/app/models/project_group_link.rb @@ -4,7 +4,8 @@ class ProjectGroupLink < ActiveRecord::Base GUEST = 10 REPORTER = 20 DEVELOPER = 30 - MASTER = 40 + MAINTAINER = 40 + MASTER = MAINTAINER # @deprecated belongs_to :project belongs_to :group diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 9a38806baab..c7d0f49d837 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -19,10 +19,13 @@ class ProjectTeam add_user(user, :developer, current_user: current_user) end - def add_master(user, current_user: nil) - add_user(user, :master, current_user: current_user) + def add_maintainer(user, current_user: nil) + add_user(user, :maintainer, current_user: current_user) end + # @deprecated + alias_method :add_master, :add_maintainer + def add_role(user, role, current_user: nil) public_send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend end @@ -81,10 +84,13 @@ class ProjectTeam @developers ||= fetch_members(Gitlab::Access::DEVELOPER) end - def masters - @masters ||= fetch_members(Gitlab::Access::MASTER) + def maintainers + @maintainers ||= fetch_members(Gitlab::Access::MAINTAINER) end + # @deprecated + alias_method :masters, :maintainers + def owners @owners ||= if group @@ -136,10 +142,13 @@ class ProjectTeam max_member_access(user.id) == Gitlab::Access::DEVELOPER end - def master?(user) - max_member_access(user.id) == Gitlab::Access::MASTER + def maintainer?(user) + max_member_access(user.id) == Gitlab::Access::MAINTAINER end + # @deprecated + alias_method :master?, :maintainer? + # Checks if `user` is authorized for this project, with at least the # `min_access_level` (if given). def member?(user, min_access_level = Gitlab::Access::GUEST) diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index fc868c3ebb7..9ae2fb0013a 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -20,7 +20,6 @@ class ProjectWiki @user = user end - delegate :empty?, to: :pages delegate :repository_storage, :hashed_storage?, to: :project def path @@ -74,6 +73,10 @@ class ProjectWiki !!find_page('home') end + def empty? + pages(limit: 1).empty? + end + # Returns an Array of Gitlab WikiPage instances or an # empty Array if this Wiki has no pages. def pages(limit: nil) diff --git a/app/models/todo.rb b/app/models/todo.rb index 942cbb754e3..a2ab405fdbe 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -22,18 +22,15 @@ class Todo < ActiveRecord::Base belongs_to :author, class_name: "User" belongs_to :note belongs_to :project - belongs_to :group belongs_to :target, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :user delegate :name, :email, to: :author, prefix: true, allow_nil: true - validates :action, :target_type, :user, presence: true + validates :action, :project, :target_type, :user, presence: true validates :author, presence: true validates :target_id, presence: true, unless: :for_commit? validates :commit_id, presence: true, if: :for_commit? - validates :project, presence: true, unless: :group_id - validates :group, presence: true, unless: :project_id scope :pending, -> { with_state(:pending) } scope :done, -> { with_state(:done) } @@ -47,7 +44,7 @@ class Todo < ActiveRecord::Base state :done end - after_save :keep_around_commit, if: :commit_id + after_save :keep_around_commit class << self # Priority sorting isn't displayed in the dropdown, because we don't show @@ -82,10 +79,6 @@ class Todo < ActiveRecord::Base end end - def parent - project - end - def unmergeable? action == UNMERGEABLE end diff --git a/app/models/user.rb b/app/models/user.rb index 1c5d39db118..4987d01aac6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -99,7 +99,8 @@ class User < ActiveRecord::Base has_many :group_members, -> { where(requested_at: nil) }, source: 'GroupMember' has_many :groups, through: :group_members has_many :owned_groups, -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :group - has_many :masters_groups, -> { where(members: { access_level: Gitlab::Access::MASTER }) }, through: :group_members, source: :group + has_many :maintainers_groups, -> { where(members: { access_level: Gitlab::Access::MAINTAINER }) }, through: :group_members, source: :group + alias_attribute :masters_groups, :maintainers_groups # Projects has_many :groups_projects, through: :groups, source: :projects @@ -728,7 +729,7 @@ class User < ActiveRecord::Base end def several_namespaces? - owned_groups.any? || masters_groups.any? + owned_groups.any? || maintainers_groups.any? end def namespace_id @@ -974,15 +975,15 @@ class User < ActiveRecord::Base end def manageable_groups - union_sql = Gitlab::SQL::Union.new([owned_groups.select(:id), masters_groups.select(:id)]).to_sql + union_sql = Gitlab::SQL::Union.new([owned_groups.select(:id), maintainers_groups.select(:id)]).to_sql # Update this line to not use raw SQL when migrated to Rails 5.2. # Either ActiveRecord or Arel constructions are fine. # This was replaced with the raw SQL construction because of bugs in the arel gem. # Bugs were fixed in arel 9.0.0 (Rails 5.2). - owned_and_master_groups = Group.where("namespaces.id IN (#{union_sql})") # rubocop:disable GitlabSecurity/SqlInjection + owned_and_maintainer_groups = Group.where("namespaces.id IN (#{union_sql})") # rubocop:disable GitlabSecurity/SqlInjection - Gitlab::GroupHierarchy.new(owned_and_master_groups).base_and_descendants + Gitlab::GroupHierarchy.new(owned_and_maintainer_groups).base_and_descendants end def namespaces @@ -1023,11 +1024,11 @@ class User < ActiveRecord::Base def ci_owned_runners @ci_owned_runners ||= begin project_runner_ids = Ci::RunnerProject - .where(project: authorized_projects(Gitlab::Access::MASTER)) + .where(project: authorized_projects(Gitlab::Access::MAINTAINER)) .select(:runner_id) group_runner_ids = Ci::RunnerNamespace - .where(namespace_id: owned_or_masters_groups.select(:id)) + .where(namespace_id: owned_or_maintainers_groups.select(:id)) .select(:runner_id) union = Gitlab::SQL::Union.new([project_runner_ids, group_runner_ids]) @@ -1236,11 +1237,14 @@ class User < ActiveRecord::Base !terms_accepted? end - def owned_or_masters_groups - union = Gitlab::SQL::Union.new([owned_groups, masters_groups]) + def owned_or_maintainers_groups + union = Gitlab::SQL::Union.new([owned_groups, maintainers_groups]) Group.from("(#{union.to_sql}) namespaces") end + # @deprecated + alias_method :owned_or_masters_groups, :owned_or_maintainers_groups + protected # override, from Devise::Validatable diff --git a/app/policies/clusters/cluster_policy.rb b/app/policies/clusters/cluster_policy.rb index 1f7c13072b9..b5b24491655 100644 --- a/app/policies/clusters/cluster_policy.rb +++ b/app/policies/clusters/cluster_policy.rb @@ -4,7 +4,7 @@ module Clusters delegate { cluster.project } - rule { can?(:master_access) }.policy do + rule { can?(:maintainer_access) }.policy do enable :update_cluster enable :admin_cluster end diff --git a/app/policies/deploy_token_policy.rb b/app/policies/deploy_token_policy.rb index 7aa9106e8b1..d1b459cfc90 100644 --- a/app/policies/deploy_token_policy.rb +++ b/app/policies/deploy_token_policy.rb @@ -1,10 +1,10 @@ class DeployTokenPolicy < BasePolicy with_options scope: :subject, score: 0 - condition(:master) { @subject.project.team.master?(@user) } + condition(:maintainer) { @subject.project.team.maintainer?(@user) } rule { anonymous }.prevent_all - rule { master }.policy do + rule { maintainer }.policy do enable :create_deploy_token enable :update_deploy_token end diff --git a/app/policies/environment_policy.rb b/app/policies/environment_policy.rb index 375a5535359..978dc3a7c81 100644 --- a/app/policies/environment_policy.rb +++ b/app/policies/environment_policy.rb @@ -1,9 +1,13 @@ class EnvironmentPolicy < BasePolicy delegate { @subject.project } - condition(:stop_action_allowed) do - @subject.stop_action? && can?(:update_build, @subject.stop_action) + condition(:stop_with_deployment_allowed) do + @subject.stop_action? && can?(:create_deployment) && can?(:update_build, @subject.stop_action) end - rule { can?(:create_deployment) & stop_action_allowed }.enable :stop_environment + condition(:stop_with_update_allowed) do + !@subject.stop_action? && can?(:update_environment, @subject) + end + + rule { stop_with_deployment_allowed | stop_with_update_allowed }.enable :stop_environment end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index ded9fe30eff..dc339b71ec7 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -11,7 +11,7 @@ class GroupPolicy < BasePolicy condition(:guest) { access_level >= GroupMember::GUEST } condition(:developer) { access_level >= GroupMember::DEVELOPER } condition(:owner) { access_level >= GroupMember::OWNER } - condition(:master) { access_level >= GroupMember::MASTER } + condition(:maintainer) { access_level >= GroupMember::MAINTAINER } condition(:reporter) { access_level >= GroupMember::REPORTER } condition(:nested_groups_supported, scope: :global) { Group.supports_nested_groups? } @@ -59,7 +59,7 @@ class GroupPolicy < BasePolicy enable :admin_issue end - rule { master }.policy do + rule { maintainer }.policy do enable :create_projects enable :admin_pipeline enable :admin_build diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 199bcf92b21..bc49092633f 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -46,7 +46,7 @@ class ProjectPolicy < BasePolicy condition(:developer) { team_access_level >= Gitlab::Access::DEVELOPER } desc "User has maintainer access" - condition(:master) { team_access_level >= Gitlab::Access::MASTER } + condition(:maintainer) { team_access_level >= Gitlab::Access::MAINTAINER } desc "Project is public" condition(:public_project, scope: :subject, score: 0) { project.public? } @@ -123,14 +123,14 @@ class ProjectPolicy < BasePolicy rule { guest }.enable :guest_access rule { reporter }.enable :reporter_access rule { developer }.enable :developer_access - rule { master }.enable :master_access + rule { maintainer }.enable :maintainer_access rule { owner | admin }.enable :owner_access rule { can?(:owner_access) }.policy do enable :guest_access enable :reporter_access enable :developer_access - enable :master_access + enable :maintainer_access enable :change_namespace enable :change_visibility_level @@ -228,7 +228,7 @@ class ProjectPolicy < BasePolicy enable :create_deployment end - rule { can?(:master_access) }.policy do + rule { can?(:maintainer_access) }.policy do enable :push_to_delete_protected_branch enable :update_project_snippet enable :update_environment diff --git a/app/serializers/environment_entity.rb b/app/serializers/environment_entity.rb index ba0ae6ba8a0..0fc3f92b151 100644 --- a/app/serializers/environment_entity.rb +++ b/app/serializers/environment_entity.rb @@ -7,7 +7,7 @@ class EnvironmentEntity < Grape::Entity expose :external_url expose :environment_type expose :last_deployment, using: DeploymentEntity - expose :stop_action? + expose :stop_action?, as: :has_stop_action expose :metrics_path, if: -> (environment, _) { environment.has_metrics? } do |environment| metrics_project_environment_path(environment.project, environment) @@ -31,4 +31,14 @@ class EnvironmentEntity < Grape::Entity end expose :created_at, :updated_at + + expose :can_stop do |environment| + environment.available? && can?(current_user, :stop_environment, environment) + end + + private + + def current_user + request.current_user + end end diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb index 5c337a9faa5..c2dfbac5414 100644 --- a/app/services/groups/nested_create_service.rb +++ b/app/services/groups/nested_create_service.rb @@ -1,11 +1,12 @@ module Groups class NestedCreateService < Groups::BaseService - attr_reader :group_path + attr_reader :group_path, :visibility_level def initialize(user, params) @current_user, @params = user, params.dup - @group_path = @params.delete(:group_path) + @visibility_level = @params.delete(:visibility_level) || + Gitlab::CurrentSettings.current_application_settings.default_group_visibility end def execute @@ -36,11 +37,12 @@ module Groups new_params = params.reverse_merge( path: subgroup_name, name: subgroup_name, - parent: last_group + parent: last_group, + visibility_level: visibility_level ) - new_params[:visibility_level] ||= Gitlab::CurrentSettings.current_application_settings.default_group_visibility - last_group = namespace_or_group(partial_path) || Groups::CreateService.new(current_user, new_params).execute + last_group = namespace_or_group(partial_path) || + Groups::CreateService.new(current_user, new_params).execute end last_group diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 8c6221af788..d7be9a925b5 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -274,9 +274,9 @@ class NotificationService def new_access_request(member) return true unless member.notifiable?(:subscription) - recipients = member.source.members.active_without_invites_and_requests.owners_and_masters - if fallback_to_group_owners_masters?(recipients, member) - recipients = member.source.group.members.active_without_invites_and_requests.owners_and_masters + recipients = member.source.members.active_without_invites_and_requests.owners_and_maintainers + if fallback_to_group_owners_maintainers?(recipients, member) + recipients = member.source.group.members.active_without_invites_and_requests.owners_and_maintainers end recipients.each { |recipient| deliver_access_request_email(recipient, member) } @@ -519,7 +519,7 @@ class NotificationService return [] unless project - notifiable_users(project.team.masters, :watch, target: project) + notifiable_users(project.team.maintainers, :watch, target: project) end def notifiable?(*args) @@ -534,7 +534,7 @@ class NotificationService mailer.member_access_requested_email(member.real_source_type, member.id, recipient.user.notification_email).deliver_later end - def fallback_to_group_owners_masters?(recipients, member) + def fallback_to_group_owners_maintainers?(recipients, member) return false if recipients.present? member.source.respond_to?(:group) && member.source.group diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 172497b8e67..85491089d8e 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -115,7 +115,7 @@ module Projects @project.group.refresh_members_authorized_projects(blocking: false) current_user.refresh_authorized_projects else - @project.add_master(@project.namespace.owner, current_user: current_user) + @project.add_maintainer(@project.namespace.owner, current_user: current_user) end end diff --git a/app/services/protected_branches/access_level_params.rb b/app/services/protected_branches/access_level_params.rb index 253ae8b0124..4658b0e850d 100644 --- a/app/services/protected_branches/access_level_params.rb +++ b/app/services/protected_branches/access_level_params.rb @@ -14,7 +14,7 @@ module ProtectedBranches private def params_with_default(params) - params[:"#{type}_access_level"] ||= Gitlab::Access::MASTER if use_default_access_level?(params) + params[:"#{type}_access_level"] ||= Gitlab::Access::MAINTAINER if use_default_access_level?(params) params end diff --git a/app/services/protected_branches/legacy_api_create_service.rb b/app/services/protected_branches/legacy_api_create_service.rb index e358fd0374e..bb7656489c5 100644 --- a/app/services/protected_branches/legacy_api_create_service.rb +++ b/app/services/protected_branches/legacy_api_create_service.rb @@ -9,14 +9,14 @@ module ProtectedBranches if params.delete(:developers_can_push) Gitlab::Access::DEVELOPER else - Gitlab::Access::MASTER + Gitlab::Access::MAINTAINER end merge_access_level = if params.delete(:developers_can_merge) Gitlab::Access::DEVELOPER else - Gitlab::Access::MASTER + Gitlab::Access::MAINTAINER end @params.merge!(push_access_levels_attributes: [{ access_level: push_access_level }], diff --git a/app/services/protected_branches/legacy_api_update_service.rb b/app/services/protected_branches/legacy_api_update_service.rb index 33176253ca2..1df38de0e4a 100644 --- a/app/services/protected_branches/legacy_api_update_service.rb +++ b/app/services/protected_branches/legacy_api_update_service.rb @@ -17,14 +17,14 @@ module ProtectedBranches when true params[:push_access_levels_attributes] = [{ access_level: Gitlab::Access::DEVELOPER }] when false - params[:push_access_levels_attributes] = [{ access_level: Gitlab::Access::MASTER }] + params[:push_access_levels_attributes] = [{ access_level: Gitlab::Access::MAINTAINER }] end case @developers_can_merge when true params[:merge_access_levels_attributes] = [{ access_level: Gitlab::Access::DEVELOPER }] when false - params[:merge_access_levels_attributes] = [{ access_level: Gitlab::Access::MASTER }] + params[:merge_access_levels_attributes] = [{ access_level: Gitlab::Access::MAINTAINER }] end service = ProtectedBranches::UpdateService.new(@project, @current_user, @params) diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index 46f12086555..f91cd03bf5c 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -260,15 +260,15 @@ class TodoService end end - def create_mention_todos(parent, target, author, note = nil, skip_users = []) + def create_mention_todos(project, target, author, note = nil, skip_users = []) # Create Todos for directly addressed users - directly_addressed_users = filter_directly_addressed_users(parent, note || target, author, skip_users) - attributes = attributes_for_todo(parent, target, author, Todo::DIRECTLY_ADDRESSED, note) + directly_addressed_users = filter_directly_addressed_users(project, note || target, author, skip_users) + attributes = attributes_for_todo(project, target, author, Todo::DIRECTLY_ADDRESSED, note) create_todos(directly_addressed_users, attributes) # Create Todos for mentioned users - mentioned_users = filter_mentioned_users(parent, note || target, author, skip_users) - attributes = attributes_for_todo(parent, target, author, Todo::MENTIONED, note) + mentioned_users = filter_mentioned_users(project, note || target, author, skip_users) + attributes = attributes_for_todo(project, target, author, Todo::MENTIONED, note) create_todos(mentioned_users, attributes) end @@ -299,36 +299,36 @@ class TodoService def attributes_for_todo(project, target, author, action, note = nil) attributes_for_target(target).merge!( - project_id: project&.id, + project_id: project.id, author_id: author.id, action: action, note: note ) end - def filter_todo_users(users, parent, target) - reject_users_without_access(users, parent, target).uniq + def filter_todo_users(users, project, target) + reject_users_without_access(users, project, target).uniq end - def filter_mentioned_users(parent, target, author, skip_users = []) + def filter_mentioned_users(project, target, author, skip_users = []) mentioned_users = target.mentioned_users(author) - skip_users - filter_todo_users(mentioned_users, parent, target) + filter_todo_users(mentioned_users, project, target) end - def filter_directly_addressed_users(parent, target, author, skip_users = []) + def filter_directly_addressed_users(project, target, author, skip_users = []) directly_addressed_users = target.directly_addressed_users(author) - skip_users - filter_todo_users(directly_addressed_users, parent, target) + filter_todo_users(directly_addressed_users, project, target) end - def reject_users_without_access(users, parent, target) - if target.is_a?(Note) && target.for_issuable? + def reject_users_without_access(users, project, target) + if target.is_a?(Note) && (target.for_issue? || target.for_merge_request?) target = target.noteable end if target.is_a?(Issuable) select_users(users, :"read_#{target.to_ability_name}", target) else - select_users(users, :read_project, parent) + select_users(users, :read_project, project) end end diff --git a/app/uploaders/gitlab_uploader.rb b/app/uploaders/gitlab_uploader.rb index 7919f126075..719bd6ef418 100644 --- a/app/uploaders/gitlab_uploader.rb +++ b/app/uploaders/gitlab_uploader.rb @@ -71,6 +71,28 @@ class GitlabUploader < CarrierWave::Uploader::Base File.join('/', self.class.base_dir, dynamic_segment, filename) end + def cached_size + size + end + + def open + stream = + if file_storage? + File.open(path, "rb") if path + else + ::Gitlab::HttpIO.new(url, cached_size) if url + end + + return unless stream + return stream unless block_given? + + begin + yield(stream) + ensure + stream.close + end + end + private # Designed to be overridden by child uploaders that have a dynamic path diff --git a/app/uploaders/job_artifact_uploader.rb b/app/uploaders/job_artifact_uploader.rb index 855cf2fc21c..f6af023e0f9 100644 --- a/app/uploaders/job_artifact_uploader.rb +++ b/app/uploaders/job_artifact_uploader.rb @@ -18,14 +18,6 @@ class JobArtifactUploader < GitlabUploader dynamic_segment end - def open - if file_storage? - File.open(path, "rb") if path - else - ::Gitlab::Ci::Trace::HttpIO.new(url, cached_size) if url - end - end - private def dynamic_segment diff --git a/app/views/admin/application_settings/_third_party_offers.html.haml b/app/views/admin/application_settings/_third_party_offers.html.haml new file mode 100644 index 00000000000..c5d775d4bf5 --- /dev/null +++ b/app/views/admin/application_settings/_third_party_offers.html.haml @@ -0,0 +1,13 @@ +- application_setting = local_assigns.fetch(:application_setting) + += form_for application_setting, url: admin_application_settings_path, html: { class: 'fieldset-form' } do |f| + = form_errors(application_setting) + + %fieldset + .form-group + .form-check + = f.check_box :hide_third_party_offers, class: 'form-check-input' + = f.label :hide_third_party_offers, class: 'form-check-label' do + Do not display offers from third parties within GitLab + + = f.submit 'Save changes', class: "btn btn-success" diff --git a/app/views/admin/application_settings/show.html.haml b/app/views/admin/application_settings/show.html.haml index bd43504dd37..5cb8001a364 100644 --- a/app/views/admin/application_settings/show.html.haml +++ b/app/views/admin/application_settings/show.html.haml @@ -325,5 +325,16 @@ .settings-content = render partial: 'repository_mirrors_form' +%section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded) } + .settings-header + %h4 + = _('Third party offers') + %button.btn.btn-default.js-settings-toggle{ type: 'button' } + = expanded ? _('Collapse') : _('Expand') + %p + = _('Control the display of third party offers.') + .settings-content + = render 'third_party_offers', application_setting: @application_setting + = render_if_exists 'admin/application_settings/pseudonymizer_settings', expanded: expanded diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml index 37fb8fbab26..3ae9ce6c11f 100644 --- a/app/views/ci/runner/_how_to_setup_runner.html.haml +++ b/app/views/ci/runner/_how_to_setup_runner.html.haml @@ -5,7 +5,7 @@ %ol %li = _("Install a Runner compatible with GitLab CI") - = (_("(checkout the %{link} for information on how to install it).") % { link: link }).html_safe + = (_("(check out the %{link} for information on how to install it).") % { link: link }).html_safe %li = _("Specify the following URL during the Runner setup:") %code#coordinator_address= root_url(only_path: false) diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml index 8b3974d97f8..d5a9cc646a6 100644 --- a/app/views/dashboard/todos/index.html.haml +++ b/app/views/dashboard/todos/index.html.haml @@ -30,33 +30,27 @@ .todos-filters .row-content-block.second-block - = form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form d-sm-flex' do - .filter-categories.flex-fill - .filter-item.inline - - if params[:group_id].present? - = hidden_field_tag(:group_id, params[:group_id]) - = dropdown_tag(group_dropdown_label(params[:group_id], 'Group'), options: { toggle_class: 'js-group-search js-filter-submit', title: 'Filter by group', filter: true, filterInput: 'input#group-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-group js-filter-submit', - placeholder: 'Search groups', data: { data: todo_group_options, default_label: 'Group', display: 'static' } }) - .filter-item.inline - - if params[:project_id].present? - = hidden_field_tag(:project_id, params[:project_id]) - = dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit', - placeholder: 'Search projects', data: { data: todo_projects_options, default_label: 'Project', display: 'static' } }) - .filter-item.inline - - if params[:author_id].present? - = hidden_field_tag(:author_id, params[:author_id]) - = dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit', - placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author', todo_filter: true, todo_state_filter: params[:state] || 'pending' } }) - .filter-item.inline - - if params[:type].present? - = hidden_field_tag(:type, params[:type]) - = dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit', - data: { data: todo_types_options, default_label: 'Type' } }) - .filter-item.inline.actions-filter - - if params[:action_id].present? - = hidden_field_tag(:action_id, params[:action_id]) - = dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit', - data: { data: todo_actions_options, default_label: 'Action' } }) + = form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form' do + .filter-item.inline + - if params[:project_id].present? + = hidden_field_tag(:project_id, params[:project_id]) + = dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit', + placeholder: 'Search projects', data: { data: todo_projects_options, default_label: 'Project', display: 'static' } }) + .filter-item.inline + - if params[:author_id].present? + = hidden_field_tag(:author_id, params[:author_id]) + = dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit', + placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author', todo_filter: true, todo_state_filter: params[:state] || 'pending' } }) + .filter-item.inline + - if params[:type].present? + = hidden_field_tag(:type, params[:type]) + = dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit', + data: { data: todo_types_options, default_label: 'Type' } }) + .filter-item.inline.actions-filter + - if params[:action_id].present? + = hidden_field_tag(:action_id, params[:action_id]) + = dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit', + data: { data: todo_actions_options, default_label: 'Action' } }) .filter-item.sort-filter .dropdown %button.dropdown-menu-toggle.dropdown-menu-toggle-sort{ type: 'button', 'data-toggle' => 'dropdown' } diff --git a/app/views/explore/_head.html.haml b/app/views/explore/_head.html.haml index a3b0709e261..eefc797cf03 100644 --- a/app/views/explore/_head.html.haml +++ b/app/views/explore/_head.html.haml @@ -1,6 +1,6 @@ .explore-title.text-center %h2 - Explore GitLab + = _("Explore GitLab") %p.lead - Discover projects, groups and snippets. Share your projects with others + = _("Discover projects, groups and snippets. Share your projects with others") %br diff --git a/app/views/explore/groups/_nav.html.haml b/app/views/explore/groups/_nav.html.haml index ab4787c6d05..c337149a2f3 100644 --- a/app/views/explore/groups/_nav.html.haml +++ b/app/views/explore/groups/_nav.html.haml @@ -2,7 +2,7 @@ %ul.nav-links.nav.nav-tabs = nav_link(page: explore_groups_path) do = link_to explore_groups_path do - Explore Groups + = _("Explore Groups") .nav-controls = render 'shared/groups/search_form' = render 'shared/groups/dropdown' diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml index 0643b9cfbc5..387c37b7a91 100644 --- a/app/views/explore/groups/index.html.haml +++ b/app/views/explore/groups/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Groups" -- header_title "Groups", dashboard_groups_path +- page_title _("Groups") +- header_title _("Groups"), dashboard_groups_path - if current_user = render 'dashboard/groups_head' @@ -10,14 +10,14 @@ - if cookies[:explore_groups_landing_dismissed] != 'true' .explore-groups.landing.content-block.js-explore-groups-landing.hide - %button.dismiss-button{ type: 'button', 'aria-label' => 'Dismiss' }= icon('times') + %button.dismiss-button{ type: 'button', 'aria-label' => _('Dismiss') }= icon('times') .svg-container = custom_icon('icon_explore_groups_splash') .inner-content - %p Below you will find all the groups that are public. - %p You can easily contribute to them by requesting to join these groups. + %p= _("Below you will find all the groups that are public.") + %p= _("You can easily contribute to them by requesting to join these groups.") - if params[:filter].blank? && @groups.empty? - .nothing-here-block No public groups + .nothing-here-block= _("No public groups") - else = render 'groups' diff --git a/app/views/explore/projects/_filter.html.haml b/app/views/explore/projects/_filter.html.haml index 6abb56ba6d2..b694103ccaf 100644 --- a/app/views/explore/projects/_filter.html.haml +++ b/app/views/explore/projects/_filter.html.haml @@ -2,16 +2,16 @@ .dropdown %button.dropdown-toggle{ href: '#', "data-toggle" => "dropdown", 'data-display' => 'static' } = icon('globe') - %span.light Visibility: + %span.light= _("Visibility:") - if params[:visibility_level].present? = visibility_level_label(params[:visibility_level].to_i) - else - Any + = _('Any') = icon('chevron-down') %ul.dropdown-menu.dropdown-menu-right %li = link_to filter_projects_path(visibility_level: nil) do - Any + = _('Any') - Gitlab::VisibilityLevel.values.each do |level| %li{ class: active_when(level.to_s == params[:visibility_level]) || 'light' } = link_to filter_projects_path(visibility_level: level) do diff --git a/app/views/explore/projects/_nav.html.haml b/app/views/explore/projects/_nav.html.haml index 558cd26f1e0..bf65c19b720 100644 --- a/app/views/explore/projects/_nav.html.haml +++ b/app/views/explore/projects/_nav.html.haml @@ -2,13 +2,13 @@ %ul.nav-links.nav.nav-tabs = nav_link(page: [trending_explore_projects_path, explore_root_path]) do = link_to trending_explore_projects_path do - Trending + = _('Trending') = nav_link(page: starred_explore_projects_path) do = link_to starred_explore_projects_path do - Most stars + = _('Most stars') = nav_link(page: explore_projects_path) do = link_to explore_projects_path do - All + = _('All') .nav-controls - unless current_user diff --git a/app/views/explore/projects/index.html.haml b/app/views/explore/projects/index.html.haml index f00802e0af7..452f390695c 100644 --- a/app/views/explore/projects/index.html.haml +++ b/app/views/explore/projects/index.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Projects" -- header_title "Projects", dashboard_projects_path +- page_title _("Projects") +- header_title _("Projects"), dashboard_projects_path - if current_user = render 'dashboard/projects_head' diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml index f00802e0af7..452f390695c 100644 --- a/app/views/explore/projects/starred.html.haml +++ b/app/views/explore/projects/starred.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Projects" -- header_title "Projects", dashboard_projects_path +- page_title _("Projects") +- header_title _("Projects"), dashboard_projects_path - if current_user = render 'dashboard/projects_head' diff --git a/app/views/explore/projects/trending.html.haml b/app/views/explore/projects/trending.html.haml index f00802e0af7..452f390695c 100644 --- a/app/views/explore/projects/trending.html.haml +++ b/app/views/explore/projects/trending.html.haml @@ -1,6 +1,6 @@ - @hide_top_links = true -- page_title "Projects" -- header_title "Projects", dashboard_projects_path +- page_title _("Projects") +- header_title _("Projects"), dashboard_projects_path - if current_user = render 'dashboard/projects_head' diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml index 5e7be5cd37b..f0d1e837317 100644 --- a/app/views/import/_githubish_status.html.haml +++ b/app/views/import/_githubish_status.html.haml @@ -21,23 +21,13 @@ %th= _('Status') %tbody - @already_added_projects.each do |project| - %tr{ id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}" } + %tr{ id: "project_#{project.id}", class: project_status_css_class(project.import_status) } %td = provider_project_link(provider, project.import_source) %td = link_to project.full_path, [project.namespace.becomes(Namespace), project] %td.job-status - - if project.import_status == 'finished' - %span - %i.fa.fa-check - = _('Done') - - elsif project.import_status == 'started' - %i.fa.fa-spinner.fa-spin - = _('Started') - - elsif project.import_status == 'failed' - = _('Failed') - - else - = project.human_import_status_name + = render 'import/project_status', project: project - @repos.each do |repo| %tr{ id: "repo_#{repo.id}", data: { qa: { repo_path: repo.full_name } } } @@ -61,6 +51,6 @@ = has_ci_cd_only_params? ? _('Connect') : _('Import') = icon("spinner spin", class: "loading-icon") -.js-importer-status{ data: { jobs_import_path: "#{url_for([:jobs, :import, provider])}", - import_path: "#{url_for([:import, provider])}", - ci_cd_only: "#{has_ci_cd_only_params?}" } } +.js-importer-status{ data: { jobs_import_path: url_for([:jobs, :import, provider]), + import_path: url_for([:import, provider]), + ci_cd_only: has_ci_cd_only_params?.to_s } } diff --git a/app/views/import/_project_status.html.haml b/app/views/import/_project_status.html.haml new file mode 100644 index 00000000000..280bcbc1e63 --- /dev/null +++ b/app/views/import/_project_status.html.haml @@ -0,0 +1,11 @@ +- case project.import_status +- when 'finished' + = icon('check') + = _('Done') +- when 'started' + = icon("spinner spin") + = _('Started') +- when 'failed' + = _('Failed') +- else + = project.human_import_status_name diff --git a/app/views/import/manifest/_form.html.haml b/app/views/import/manifest/_form.html.haml new file mode 100644 index 00000000000..763beb5958f --- /dev/null +++ b/app/views/import/manifest/_form.html.haml @@ -0,0 +1,23 @@ += form_tag upload_import_manifest_path, multipart: true do + .form-group + = label_tag :group_id, nil, class: 'label-light' do + = _('Group') + .input-group + .input-group-prepend.has-tooltip{ title: root_url } + .input-group-text + = root_url + = select_tag :group_id, namespaces_options(nil, display_path: true, groups_only: true), { class: 'select2 js-select-namespace' } + .form-text.text-muted + = _('Choose the top-level group for your repository imports.') + + .form-group + = label_tag :manifest, class: 'label-light' do + = _('Manifest') + = file_field_tag :manifest, class: 'form-control-file', required: true + .form-text.text-muted + = _('Import multiple repositories by uploading a manifest file.') + = link_to icon('question-circle'), help_page_path('user/project/import/manifest') + + .append-bottom-10 + = submit_tag _('List available repositories'), class: 'btn btn-success' + = link_to _('Cancel'), new_project_path, class: 'btn btn-cancel' diff --git a/app/views/import/manifest/new.html.haml b/app/views/import/manifest/new.html.haml new file mode 100644 index 00000000000..056e4922b9e --- /dev/null +++ b/app/views/import/manifest/new.html.haml @@ -0,0 +1,12 @@ +- page_title "Manifest file import" +- header_title "Projects", root_path + +%h3.page-title + = _('Manifest file import') + +- if @errors.present? + .alert.alert-danger + - @errors.each do |error| + = error + += render 'form' diff --git a/app/views/import/manifest/status.html.haml b/app/views/import/manifest/status.html.haml new file mode 100644 index 00000000000..5b2e1005398 --- /dev/null +++ b/app/views/import/manifest/status.html.haml @@ -0,0 +1,42 @@ +- page_title "Manifest import" +- header_title "Projects", root_path +- provider = 'manifest' + +%h3.page-title + = _('Manifest file import') + +%p + = button_tag class: "btn btn-import btn-success js-import-all" do + = import_all_githubish_repositories_button_label + = icon("spinner spin", class: "loading-icon") + +.table-responsive + %table.table.import-jobs + %thead + %tr + %th= _('Repository URL') + %th= _('To GitLab') + %th= _('Status') + %tbody + - @already_added_projects.each do |project| + %tr{ id: "project_#{project.id}", class: project_status_css_class(project.import_status) } + %td + = project.import_url + %td + = link_to_project project + %td.job-status + = render 'import/project_status', project: project + + - @pending_repositories.each do |repository| + %tr{ id: "repo_#{repository[:id]}" } + %td + = repository[:url] + %td.import-target + = import_project_target(@group.full_path, repository[:path]) + %td.import-actions.job-status + = button_tag class: "btn btn-import js-add-to-import" do + = _('Import') + = icon("spinner spin", class: "loading-icon") + +.js-importer-status{ data: { jobs_import_path: url_for([:jobs, :import, provider]), + import_path: url_for([:import, provider]) } } diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 62402c32e08..4c73da4c75b 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -6,14 +6,14 @@ = sprite_icon('admin', size: 24) .sidebar-context-title Admin Area %ul.sidebar-top-level-items - = nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts conversational_development_index), html_options: {class: 'home'}) do + = nav_link(controller: %w(dashboard admin projects users groups jobs runners gitaly_servers cohorts conversational_development_index), html_options: {class: 'home'}) do = link_to admin_root_path, class: 'shortcuts-tree' do .nav-icon-container = sprite_icon('overview') %span.nav-item-name Overview %ul.sidebar-sub-level-items - = nav_link(controller: %w(dashboard admin projects users groups jobs runners cohorts conversational_development_index), html_options: { class: "fly-out-top-item" } ) do + = nav_link(controller: %w(dashboard admin projects users groups jobs runners gitaly_servers cohorts conversational_development_index), html_options: { class: "fly-out-top-item" } ) do = link_to admin_root_path do %strong.fly-out-top-item-name #{ _('Overview') } @@ -42,6 +42,10 @@ = link_to admin_runners_path, title: 'Runners' do %span Runners + = nav_link(controller: :gitaly_servers) do + = link_to admin_gitaly_servers_path, title: 'Gitaly Servers' do + %span + Gitaly Servers = nav_link path: 'cohorts#index' do = link_to admin_cohorts_path, title: 'Cohorts' do %span diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index 00d75b3399b..33de74dbaa2 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -122,7 +122,7 @@ = render_if_exists 'projects/sidebar/issues_service_desk' = nav_link(controller: :milestones) do - = link_to project_milestones_path(@project), title: 'Milestones' do + = link_to project_milestones_path(@project), title: 'Milestones', class: 'qa-milestones-link' do %span = _('Milestones') - if project_nav_tab? :external_issue_tracker diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml index ccb724a3b0f..246e09d7677 100644 --- a/app/views/projects/_import_project_pane.html.haml +++ b/app/views/projects/_import_project_pane.html.haml @@ -1,54 +1,67 @@ - active_tab = local_assigns.fetch(:active_tab, 'blank') -- f = local_assigns.fetch(:f) .project-import .form-group.import-btn-container.clearfix - = f.label :visibility_level, class: 'label-light' do #the label here seems wrong + %h5 Import project from .import-buttons - if gitlab_project_import_enabled? .import_gitlab_project.has-tooltip{ data: { container: 'body' } } = link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do = icon('gitlab', text: 'GitLab export') - %div - - if github_import_enabled? + + - if github_import_enabled? + %div = link_to new_import_github_path, class: 'btn js-import-github' do = icon('github', text: 'GitHub') - %div - - if bitbucket_import_enabled? + + - if bitbucket_import_enabled? + %div = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}" do = icon('bitbucket', text: 'Bitbucket Cloud') - unless bitbucket_import_configured? = render 'bitbucket_import_modal' - %div - - if bitbucket_server_import_enabled? + - if bitbucket_server_import_enabled? + %div = link_to status_import_bitbucket_server_path, class: "btn import_bitbucket" do = icon('bitbucket', text: 'Bitbucket Server') = render 'bitbucket_import_modal' - %div - - if gitlab_import_enabled? + %div + - if gitlab_import_enabled? + %div = link_to status_import_gitlab_path, class: "btn import_gitlab #{'how_to_import_link' unless gitlab_import_configured?}" do = icon('gitlab', text: 'GitLab.com') - unless gitlab_import_configured? = render 'gitlab_import_modal' - %div - - if google_code_import_enabled? + + - if google_code_import_enabled? + %div = link_to new_import_google_code_path, class: 'btn import_google_code' do = icon('google', text: 'Google Code') - %div - - if fogbugz_import_enabled? + + - if fogbugz_import_enabled? + %div = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do = icon('bug', text: 'Fogbugz') - %div - - if gitea_import_enabled? + + - if gitea_import_enabled? + %div = link_to new_import_gitea_path, class: 'btn import_gitea' do = custom_icon('go_logo') Gitea - %div - - if git_import_enabled? + + - if git_import_enabled? + %div %button.btn.js-toggle-button.js-import-git-toggle-button{ type: "button", data: { toggle_open_class: 'active' } } = icon('git', text: 'Repo by URL') + + - if manifest_import_enabled? + %div + = link_to new_import_manifest_path, class: 'btn import_manifest' do + = icon('file-text-o', text: 'Manifest file') + .js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') } - %hr + = form_for @project, html: { class: 'new_project' } do |f| + %hr = render "shared/import_form", f: f = render 'new_project_fields', f: f, project_name_id: "import-url-name" diff --git a/app/views/projects/deployments/_actions.haml b/app/views/projects/deployments/_actions.haml index e0ecf56525a..f4c91377ecb 100644 --- a/app/views/projects/deployments/_actions.haml +++ b/app/views/projects/deployments/_actions.haml @@ -3,13 +3,12 @@ - if actions.present? .btn-group .dropdown - %button.dropdown.dropdown-new.btn.btn-default{ type: 'button', 'data-toggle' => 'dropdown' } - = custom_icon('icon_play') + %button.dropdown.dropdown-new.btn.btn-default.has-tooltip{ type: 'button', 'data-toggle' => 'dropdown', title: s_('Environments|Deploy to...') } + = sprite_icon('play') = icon('caret-down') %ul.dropdown-menu.dropdown-menu-right - actions.each do |action| - next unless can?(current_user, :update_build, action) %li - = link_to [:play, @project.namespace.becomes(Namespace), @project, action], method: :post, rel: 'nofollow' do - = custom_icon('icon_play') + = link_to [:play, @project.namespace.becomes(Namespace), @project, action], method: :post, rel: 'nofollow', class: 'btn' do %span= action.name.humanize diff --git a/app/views/projects/deployments/_rollback.haml b/app/views/projects/deployments/_rollback.haml index 95f950948ab..281e042c915 100644 --- a/app/views/projects/deployments/_rollback.haml +++ b/app/views/projects/deployments/_rollback.haml @@ -1,6 +1,7 @@ - if can?(current_user, :create_deployment, deployment) && deployment.deployable - = link_to [:retry, @project.namespace.becomes(Namespace), @project, deployment.deployable], method: :post, class: 'btn btn-build' do + - tooltip = deployment.last? ? s_('Environments|Re-deploy to environment') : s_('Environments|Rollback environment') + = link_to [:retry, @project.namespace.becomes(Namespace), @project, deployment.deployable], method: :post, class: 'btn btn-build has-tooltip', title: tooltip do - if deployment.last? - = _("Re-deploy") + = sprite_icon('repeat') - else - = _("Rollback") + = sprite_icon('redo') diff --git a/app/views/projects/environments/_external_url.html.haml b/app/views/projects/environments/_external_url.html.haml index a264252e095..4694bc39d54 100644 --- a/app/views/projects/environments/_external_url.html.haml +++ b/app/views/projects/environments/_external_url.html.haml @@ -1,4 +1,4 @@ - if environment.external_url && can?(current_user, :read_environment, environment) - = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url' do + = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url has-tooltip', title: s_('Environments|Open live environment') do = sprite_icon('external-link') View deployment diff --git a/app/views/projects/environments/_stop.html.haml b/app/views/projects/environments/_stop.html.haml deleted file mode 100644 index c35f9af2873..00000000000 --- a/app/views/projects/environments/_stop.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -- if can?(current_user, :create_deployment, environment) && environment.stop_action? - .inline - = link_to stop_project_environment_path(@project, environment), method: :post, - class: 'btn stop-env-link', rel: 'nofollow', data: { confirm: 'Are you sure you want to stop this environment?' } do - = icon('stop', class: 'stop-env-icon') diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index add394a6356..a33bc9d4ce6 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -4,6 +4,33 @@ - page_title "Environments" %div{ class: container_class } + - if can?(current_user, :stop_environment, @environment) + #stop-environment-modal.modal.fade{ tabindex: -1 } + .modal-dialog + .modal-content + .modal-header + %h4.modal-title.d-flex.mw-100 + Stopping + %span.has-tooltip.text-truncate.ml-1.mr-1.flex-fill{ title: @environment.name, data: { container: '#stop-environment-modal' } } + = @environment.name + ? + .modal-body + %p= s_('Environments|Are you sure you want to stop this environment?') + - unless @environment.stop_action? + .warning_message + %p= s_('Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file.').html_safe % { emphasis_start: '<strong>'.html_safe, + emphasis_end: '</strong>'.html_safe, + ci_config_link_start: '<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">'.html_safe, + ci_config_link_end: '</a>'.html_safe } + %a{ href: 'https://docs.gitlab.com/ee/ci/environments.html#stopping-an-environment', + target: '_blank', + rel: 'noopener noreferrer' } + = s_('Environments|Learn more about stopping environments') + .modal-footer + = button_tag _('Cancel'), type: 'button', class: 'btn btn-cancel', data: { dismiss: 'modal' } + = button_to stop_project_environment_path(@project, @environment), class: 'btn btn-danger has-tooltip', method: :post do + = s_('Environments|Stop environment') + .row.top-area.adjust .col-md-7 %h3.page-title= @environment.name @@ -15,7 +42,10 @@ - if can?(current_user, :update_environment, @environment) = link_to 'Edit', edit_project_environment_path(@project, @environment), class: 'btn' - if can?(current_user, :stop_environment, @environment) - = link_to 'Stop', stop_project_environment_path(@project, @environment), data: { confirm: 'Are you sure you want to stop this environment?' }, class: 'btn btn-danger', method: :post + = button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal', + target: '#stop-environment-modal' } do + = sprite_icon('stop') + = s_('Environments|Stop') .environments-container - if @deployments.blank? diff --git a/app/views/projects/merge_requests/_mr_box.html.haml b/app/views/projects/merge_requests/_mr_box.html.haml index 8a390cf8700..1a9ab288683 100644 --- a/app/views/projects/merge_requests/_mr_box.html.haml +++ b/app/views/projects/merge_requests/_mr_box.html.haml @@ -1,4 +1,4 @@ -.detail-page-description.content-block +.detail-page-description %h2.title = markdown_field(@merge_request, :title) diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml index ace094a671a..28f0a167128 100644 --- a/app/views/projects/milestones/_form.html.haml +++ b/app/views/projects/milestones/_form.html.haml @@ -7,12 +7,12 @@ .form-group.row = f.label :title, "Title", class: "col-form-label col-sm-2" .col-sm-10 - = f.text_field :title, maxlength: 255, class: "form-control", required: true, autofocus: true + = f.text_field :title, maxlength: 255, class: "qa-milestone-title form-control", required: true, autofocus: true .form-group.row.milestone-description = f.label :description, "Description", class: "col-form-label col-sm-2" .col-sm-10 = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project) } do - = render 'projects/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: 'Write milestone description...' + = render 'projects/zen', f: f, attr: :description, classes: 'qa-milestone-description note-textarea', placeholder: 'Write milestone description...' = render 'shared/notes/hints' .clearfix .error-alert @@ -20,7 +20,7 @@ .form-actions - if @milestone.new_record? - = f.submit 'Create milestone', class: "btn-create btn" + = f.submit 'Create milestone', class: "btn-create btn qa-milestone-create-button" = link_to "Cancel", project_milestones_path(@project), class: "btn btn-cancel" - else = f.submit 'Save changes', class: "btn-save btn" diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index 5b0197ed58c..26d2ea8447b 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -8,7 +8,7 @@ .nav-controls = render 'shared/milestones_sort_dropdown' - if can?(current_user, :admin_milestone, @project) - = link_to new_project_milestone_path(@project), class: "btn btn-new", title: 'New milestone' do + = link_to new_project_milestone_path(@project), class: "btn btn-new qa-new-project-milestone", title: 'New milestone' do New milestone .milestones diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index f7b04c436a6..2a9e20c2caa 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -60,7 +60,7 @@ = icon('angle-double-left') .detail-page-description.milestone-detail - %h2.title + %h2.title.qa-milestone-title = markdown_field(@milestone, :title) %div diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 5bb1bfb7059..6c363345e38 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -55,13 +55,12 @@ = render 'project_templates', f: f .tab-pane.import-project-pane.js-toggle-container{ id: 'import-project-pane', class: active_when(active_tab == 'import'), role: 'tabpanel' } - = form_for @project, html: { class: 'new_project' } do |f| - - if import_sources_enabled? - = render 'import_project_pane', f: f, active_tab: active_tab - - else - .nothing-here-block - %h4 No import options available - %p Contact an administrator to enable options for importing your project. + - if import_sources_enabled? + = render 'import_project_pane', active_tab: active_tab + - else + .nothing-here-block + %h4 No import options available + %p Contact an administrator to enable options for importing your project. .save-project-loader.d-none .center diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index ac2ebb701a5..d38d161047b 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -1,7 +1,7 @@ - if any_projects?(@projects) .project-item-select-holder.btn-group - %a.btn.btn-new.new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } } + %a.btn.btn-new.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } } = icon('spinner spin') = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path] }, with_feature_enabled: local_assigns[:with_feature_enabled] - %button.btn.btn-new.new-project-item-select-button + %button.btn.btn-new.new-project-item-select-button.qa-new-project-item-select-button = icon('caret-down') diff --git a/app/views/shared/issuable/_milestone_dropdown.html.haml b/app/views/shared/issuable/_milestone_dropdown.html.haml index 37625a4a163..c2da363b8c6 100644 --- a/app/views/shared/issuable/_milestone_dropdown.html.haml +++ b/app/views/shared/issuable/_milestone_dropdown.html.haml @@ -7,7 +7,7 @@ - dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by milestone") - if selected.present? || params[:milestone_title].present? = hidden_field_tag(name, name == :milestone_title ? selected_text : selected.id) -= dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", += dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "qa-issuable-milestone-dropdown js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "qa-issuable-dropdown-menu-milestone dropdown-menu-selectable dropdown-menu-milestone", placeholder: "Search milestones", footer_content: project.present?, data: { show_no: true, show_menu_above: show_menu_above, show_any: show_any, show_upcoming: show_upcoming, show_started: show_started, field_name: name, selected: selected_text, project_id: project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do - if project %ul.dropdown-footer-list diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml index bd87bb38e77..3b017c62a80 100644 --- a/app/views/shared/issuable/form/_metadata.html.haml +++ b/app/views/shared/issuable/form/_metadata.html.haml @@ -18,7 +18,7 @@ = form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}" .col-sm-10{ class: ("col-md-8" if has_due_date) } .issuable-form-select-holder - = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" + = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "qa-issuable-milestone-dropdown js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" .form-group.row - has_labels = @labels && @labels.any? = form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}" diff --git a/app/views/shared/notes/_form.html.haml b/app/views/shared/notes/_form.html.haml index 6b2715b47a7..c360f1ffe2a 100644 --- a/app/views/shared/notes/_form.html.haml +++ b/app/views/shared/notes/_form.html.haml @@ -40,5 +40,5 @@ = yield(:note_actions) - %a.btn.btn-cancel.js-note-discard{ role: "button", data: {cancel_text: "Discard draft" } } + %a.btn.btn-cancel.js-note-discard{ role: "button", data: {cancel_text: "Cancel" } } Discard draft diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb index fd49bc18161..2d381c6fd6c 100644 --- a/app/workers/git_garbage_collect_worker.rb +++ b/app/workers/git_garbage_collect_worker.rb @@ -65,10 +65,10 @@ class GitGarbageCollectWorker client.repack_incremental end rescue GRPC::NotFound => e - Gitlab::GitLogger.error("#{method} failed:\nRepository not found") + Gitlab::GitLogger.error("#{__method__} failed:\nRepository not found") raise Gitlab::Git::Repository::NoRepository.new(e) rescue GRPC::BadStatus => e - Gitlab::GitLogger.error("#{method} failed:\n#{e}") + Gitlab::GitLogger.error("#{__method__} failed:\n#{e}") raise Gitlab::Git::CommandError.new(e) end diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb index ed39b4a1ea8..c9f6df9b56d 100644 --- a/app/workers/process_commit_worker.rb +++ b/app/workers/process_commit_worker.rb @@ -79,9 +79,10 @@ class ProcessCommitWorker # Avoid reprocessing commits that already exist in the upstream # when project is forked. This will also prevent duplicated system notes. def commit_exists_in_upstream?(project, commit_hash) - return false unless project.forked? + upstream_project = project.fork_source + + return false unless upstream_project - upstream_project = project.forked_from_project commit_id = commit_hash.with_indifferent_access[:id] upstream_project.commit(commit_id).present? end diff --git a/bin/changelog b/bin/changelog index d7b2a1a2de9..758c036161e 100755 --- a/bin/changelog +++ b/bin/changelog @@ -23,6 +23,8 @@ module ChangelogHelpers Abort = Class.new(StandardError) Done = Class.new(StandardError) + MAX_FILENAME_LENGTH = 140 # ecryptfs has a limit of 140 characters + def capture_stdout(cmd) output = IO.popen(cmd, &:read) fail_with "command failed: #{cmd.join(' ')}" unless $?.success? @@ -142,7 +144,9 @@ class ChangelogEntry def initialize(options) @options = options + end + def execute assert_feature_branch! assert_title! assert_new_file! @@ -221,10 +225,12 @@ class ChangelogEntry end def file_path - File.join( + base_path = File.join( unreleased_path, - branch_name.gsub(/[^\w-]/, '-') << '.yml' - ) + branch_name.gsub(/[^\w-]/, '-')) + + # Add padding for .yml extension + base_path[0..MAX_FILENAME_LENGTH - 5] + '.yml' end def unreleased_path @@ -250,7 +256,7 @@ end if $0 == __FILE__ begin options = ChangelogOptionParser.parse(ARGV) - ChangelogEntry.new(options) + ChangelogEntry.new(options).execute rescue ChangelogHelpers::Abort => ex $stderr.puts ex.message exit 1 diff --git a/changelogs/unreleased/42415-omit-projects-from-get-group-endpoint.yml b/changelogs/unreleased/42415-omit-projects-from-get-group-endpoint.yml new file mode 100644 index 00000000000..cabe5216045 --- /dev/null +++ b/changelogs/unreleased/42415-omit-projects-from-get-group-endpoint.yml @@ -0,0 +1,5 @@ +--- +title: Adds with_projects optional parameter to GET /groups/:id API endpoint +merge_request: 20494 +author: +type: changed diff --git a/changelogs/unreleased/46930-fix-updated_at-if-created_at-is-set-note-api.yml b/changelogs/unreleased/46930-fix-updated_at-if-created_at-is-set-note-api.yml new file mode 100644 index 00000000000..d95714a5267 --- /dev/null +++ b/changelogs/unreleased/46930-fix-updated_at-if-created_at-is-set-note-api.yml @@ -0,0 +1,5 @@ +--- +title: Fix updated_at if created_at is set for Note API +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/48237-toggle-file-comments.yml b/changelogs/unreleased/48237-toggle-file-comments.yml new file mode 100644 index 00000000000..2e893aad0b2 --- /dev/null +++ b/changelogs/unreleased/48237-toggle-file-comments.yml @@ -0,0 +1,5 @@ +--- +title: Fixes toggle discussion button not expanding collapsed discussions +merge_request: 20452 +author: +type: fixed diff --git a/changelogs/unreleased/48537-update-avatar-only-via-api.yml b/changelogs/unreleased/48537-update-avatar-only-via-api.yml new file mode 100644 index 00000000000..9b3ab946cc1 --- /dev/null +++ b/changelogs/unreleased/48537-update-avatar-only-via-api.yml @@ -0,0 +1,5 @@ +--- +title: Allow updating a project's avatar without other params +merge_request: +author: Jamie Schembri +type: fixed diff --git a/changelogs/unreleased/48578-disable-gcp-free-credit-banner-at-instance-level.yml b/changelogs/unreleased/48578-disable-gcp-free-credit-banner-at-instance-level.yml new file mode 100644 index 00000000000..575767df912 --- /dev/null +++ b/changelogs/unreleased/48578-disable-gcp-free-credit-banner-at-instance-level.yml @@ -0,0 +1,5 @@ +--- +title: Add option to hide third party offers in admin application settings +merge_request: 20379 +author: +type: added diff --git a/changelogs/unreleased/48934.yml b/changelogs/unreleased/48934.yml new file mode 100644 index 00000000000..8e2e53ed198 --- /dev/null +++ b/changelogs/unreleased/48934.yml @@ -0,0 +1,5 @@ +--- +title: Improve danger confirmation modals by focusing input field +merge_request: +author: Jamie Schembri +type: added diff --git a/changelogs/unreleased/48951-clean-up.yml b/changelogs/unreleased/48951-clean-up.yml new file mode 100644 index 00000000000..0102cd43f96 --- /dev/null +++ b/changelogs/unreleased/48951-clean-up.yml @@ -0,0 +1,5 @@ +--- +title: Removes unused vuex code in mr refactor and removes unneeded dependencies +merge_request: 20499 +author: +type: other diff --git a/changelogs/unreleased/49114-add-gitaly-servers-to-admin-overview-navigation-menu.yml b/changelogs/unreleased/49114-add-gitaly-servers-to-admin-overview-navigation-menu.yml new file mode 100644 index 00000000000..ab320450a1a --- /dev/null +++ b/changelogs/unreleased/49114-add-gitaly-servers-to-admin-overview-navigation-menu.yml @@ -0,0 +1,5 @@ +--- +title: Gitaly Servers link into Admin > Overview navigation menu +merge_request: 20550 +author: +type: added diff --git a/changelogs/unreleased/add-dst-support-to-pipeline-schedule.yml b/changelogs/unreleased/add-dst-support-to-pipeline-schedule.yml new file mode 100644 index 00000000000..08376014ad7 --- /dev/null +++ b/changelogs/unreleased/add-dst-support-to-pipeline-schedule.yml @@ -0,0 +1,5 @@ +--- +title: Add support for daylight savings time to pipleline schedules +merge_request: 20145 +author: +type: fixed diff --git a/changelogs/unreleased/dz-manifest-import.yml b/changelogs/unreleased/dz-manifest-import.yml new file mode 100644 index 00000000000..b0d29b0869f --- /dev/null +++ b/changelogs/unreleased/dz-manifest-import.yml @@ -0,0 +1,5 @@ +--- +title: Add ability to import multiple repositories by uploading a manifest file +merge_request: 20304 +author: +type: added diff --git a/changelogs/unreleased/gitaly-serverservice-info-timeout.yml b/changelogs/unreleased/gitaly-serverservice-info-timeout.yml new file mode 100644 index 00000000000..7f2fe8b9c93 --- /dev/null +++ b/changelogs/unreleased/gitaly-serverservice-info-timeout.yml @@ -0,0 +1,5 @@ +--- +title: Use appropriate timeout on Gitaly server info checks, avoid error on timeout +merge_request: 20552 +author: +type: fixed diff --git a/changelogs/unreleased/ide-row-dropdown-design-update.yml b/changelogs/unreleased/ide-row-dropdown-design-update.yml new file mode 100644 index 00000000000..e0fe64c944e --- /dev/null +++ b/changelogs/unreleased/ide-row-dropdown-design-update.yml @@ -0,0 +1,5 @@ +--- +title: Updated design of new entry dropdown in Web IDE +merge_request: 20526 +author: +type: changed diff --git a/changelogs/unreleased/improve-metadata-access-performance.yml b/changelogs/unreleased/improve-metadata-access-performance.yml new file mode 100644 index 00000000000..b16fa99dd3b --- /dev/null +++ b/changelogs/unreleased/improve-metadata-access-performance.yml @@ -0,0 +1,5 @@ +--- +title: Access metadata directly from Object Storage +merge_request: +author: +type: performance diff --git a/changelogs/unreleased/process-commits-as-normal-in-forks-with-missing-upstream.yml b/changelogs/unreleased/process-commits-as-normal-in-forks-with-missing-upstream.yml new file mode 100644 index 00000000000..6994a238074 --- /dev/null +++ b/changelogs/unreleased/process-commits-as-normal-in-forks-with-missing-upstream.yml @@ -0,0 +1,5 @@ +--- +title: Process commits as normal in forks when the upstream project is deleted +merge_request: 20534 +author: +type: fixed diff --git a/changelogs/unreleased/rails5-mysql-rename-column.yml b/changelogs/unreleased/rails5-mysql-rename-column.yml new file mode 100644 index 00000000000..cbae9250744 --- /dev/null +++ b/changelogs/unreleased/rails5-mysql-rename-column.yml @@ -0,0 +1,5 @@ +--- +title: Rails5 MySQL fix rename_column as part of cleanup_concurrent_column_type_change +merge_request: 20514 +author: Jasper Maes +type: fixed diff --git a/changelogs/unreleased/runners-max-timeout-param.yml b/changelogs/unreleased/runners-max-timeout-param.yml new file mode 100644 index 00000000000..875f805d849 --- /dev/null +++ b/changelogs/unreleased/runners-max-timeout-param.yml @@ -0,0 +1,5 @@ +--- +title: Add missing maximum_timeout parameter +merge_request: 20355 +author: gfyoung +type: fixed diff --git a/changelogs/unreleased/sh-handle-colons-in-url-passwords.yml b/changelogs/unreleased/sh-handle-colons-in-url-passwords.yml new file mode 100644 index 00000000000..7717d0aab37 --- /dev/null +++ b/changelogs/unreleased/sh-handle-colons-in-url-passwords.yml @@ -0,0 +1,5 @@ +--- +title: Properly handle colons in URL passwords +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/sh-optimize-wiki-empty-check.yml b/changelogs/unreleased/sh-optimize-wiki-empty-check.yml new file mode 100644 index 00000000000..31ca7497b5a --- /dev/null +++ b/changelogs/unreleased/sh-optimize-wiki-empty-check.yml @@ -0,0 +1,5 @@ +--- +title: Optimize ProjectWiki#empty? check +merge_request: 20573 +author: +type: performance diff --git a/changelogs/unreleased/winh-stop-all-environments.yml b/changelogs/unreleased/winh-stop-all-environments.yml new file mode 100644 index 00000000000..6e5f2f506d9 --- /dev/null +++ b/changelogs/unreleased/winh-stop-all-environments.yml @@ -0,0 +1,5 @@ +--- +title: Support manually stopping any environment from the UI +merge_request: 20077 +author: +type: changed diff --git a/config/initializers/active_record_table_definition.rb b/config/initializers/active_record_table_definition.rb index 8e3a1c7a62f..a71069f27a3 100644 --- a/config/initializers/active_record_table_definition.rb +++ b/config/initializers/active_record_table_definition.rb @@ -29,6 +29,11 @@ module ActiveRecord def datetime_with_timezone(column_name, **options) column(column_name, :datetime_with_timezone, options) end + + # Disable timestamp alias to datetime + def aliased_types(name, fallback) + fallback + end end end end diff --git a/config/routes/import.rb b/config/routes/import.rb index be3058193d5..3998d977c81 100644 --- a/config/routes/import.rb +++ b/config/routes/import.rb @@ -52,4 +52,10 @@ namespace :import do resource :gitlab_project, only: [:create, :new] do post :create end + + resource :manifest, only: [:create, :new], controller: :manifest do + get :status + get :jobs + post :upload + end end diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile new file mode 100644 index 00000000000..2424e650d07 --- /dev/null +++ b/danger/changelog/Dangerfile @@ -0,0 +1,66 @@ +# rubocop:disable Style/SignalException + +require 'yaml' + +NO_CHANGELOG_LABELS = %w[backstage QA test].freeze +SEE_DOC = "See [the documentation](https://docs.gitlab.com/ce/development/changelog.html).".freeze +MISSING_CHANGELOG_MESSAGE = <<~MSG.freeze +**[CHANGELOG missing](https://docs.gitlab.com/ce/development/changelog.html).** + +You can create one with: + +``` +bin/changelog -m %<mr_iid>s +``` + +If your merge request doesn't warrant a CHANGELOG entry, +consider adding any of the %<labels>s labels. +#{SEE_DOC} +MSG + +def ee? + ENV['CI_PROJECT_NAME'] == 'gitlab-ee' || File.exist?('../../CHANGELOG-EE.md') +end + +def ee_changelog?(changelog_path) + changelog_path =~ /unreleased-ee/ +end + +def ce_port_changelog?(changelog_path) + ee? && !ee_changelog?(changelog_path) +end + +def check_changelog(path) + yaml = YAML.safe_load(File.read(path)) + + fail "`title` should be set, in #{gitlab.html_link(path)}! #{SEE_DOC}" if yaml["title"].nil? + fail "`type` should be set, in #{gitlab.html_link(path)}! #{SEE_DOC}" if yaml["type"].nil? + + if yaml["merge_request"].nil? + message "Consider setting `merge_request` to #{gitlab.mr_json["iid"]} in #{gitlab.html_link(path)}. #{SEE_DOC}" + elsif yaml["merge_request"] != gitlab.mr_json["iid"] && !ce_port_changelog?(changelog_path) + fail "Merge request ID was not set to #{gitlab.mr_json["iid"]}! #{SEE_DOC}" + end +rescue StandardError + # YAML could not be parsed, fail the build. + fail "#{gitlab.html_link(path)} isn't valid YAML! #{SEE_DOC}" +end + +def presented_no_changelog_labels + NO_CHANGELOG_LABELS.map { |label| "~#{label}" }.join(', ') +end + +changelog_needed = (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty? +changelog_found = git.added_files.find { |path| path =~ %r{\A(ee/)?(changelogs/unreleased)(-ee)?/} } + +if git.modified_files.include?("CHANGELOG.md") + fail "CHANGELOG.md was edited. Please remove the additions and create an entry with `bin/changelog -m #{gitlab.mr_json["iid"]}` instead." +end + +if changelog_needed + if changelog_found + check_changelog(changelog_found) + else + warn format(MISSING_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], labels: presented_no_changelog_labels) + end +end diff --git a/danger/changes_size/Dangerfile b/danger/changes_size/Dangerfile new file mode 100644 index 00000000000..8251d0d5cbf --- /dev/null +++ b/danger/changes_size/Dangerfile @@ -0,0 +1,17 @@ +# FIXME: git.info_for_file raises the following error +# /usr/local/bundle/gems/git-1.4.0/lib/git/lib.rb:956:in `command': (Danger::DSLError) +# [!] Invalid `Dangerfile` file: +# [!] Invalid `Dangerfile` file: git '--git-dir=/builds/gitlab-org/gitlab-ce/.git' '--work-tree=/builds/gitlab-org/gitlab-ce' cat-file '-t' '' 2>&1:fatal: Not a valid object name +# This seems to be the same as https://github.com/danger/danger/issues/535. + +# locale_files_updated = git.modified_files.select { |path| path.start_with?('locale') } +# locale_files_updated.each do |locale_file_updated| +# git_stats = git.info_for_file(locale_file_updated) +# message "Git stats for #{locale_file_updated}: #{git_stats[:insertions]} insertions, #{git_stats[:deletions]} insertions" +# end + +if git.lines_of_code > 2_000 + warn "This merge request is definitely too big (more than #{git.lines_of_code} lines changed), please split it into multiple merge requests." +elsif git.lines_of_code > 500 + warn "This merge request is quite big (more than #{git.lines_of_code} lines changed), please consider splitting it into multiple merge requests." +end diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile new file mode 100644 index 00000000000..6f48994945a --- /dev/null +++ b/danger/database/Dangerfile @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +# All the files/directories that should be reviewed by the DB team. +DB_FILES = [ + 'db/', + 'app/models/project_authorization.rb', + 'app/services/users/refresh_authorized_projects_service.rb', + 'lib/gitlab/background_migration.rb', + 'lib/gitlab/background_migration/', + 'lib/gitlab/database.rb', + 'lib/gitlab/database/', + 'lib/gitlab/github_import.rb', + 'lib/gitlab/github_import/', + 'lib/gitlab/sql/', + 'rubocop/cop/migration', + 'ee/db/', + 'ee/lib/gitlab/database/' +].freeze + +SCHEMA_NOT_UPDATED_MESSAGE = <<~MSG +**New %<migrations>s added but %<schema>s wasn't updated.** + +Usually, when adding new %<migrations>s, %<schema>s should be +updated too (unless the migration isn't changing the DB schema +and isn't the most recent one). +MSG + +def database_paths_requiring_review(files) + to_review = [] + + files.each do |file| + review = DB_FILES.any? do |pattern| + file.start_with?(pattern) + end + + to_review << file if review + end + + to_review +end + +all_files = git.added_files + git.modified_files + +non_geo_db_schema_updated = !git.modified_files.grep(%r{\Adb/schema\.rb/}).empty? +geo_db_schema_updated = !git.modified_files.grep(%r{\Aee/db/geo/schema\.rb/}).empty? + +non_geo_migration_created = !git.added_files.grep(%r{\A(db/(post_)?migrate)/}).empty? +geo_migration_created = !git.added_files.grep(%r{\Aee/db/geo/(post_)?migrate/}).empty? + +if non_geo_migration_created && !non_geo_db_schema_updated + warn format(SCHEMA_NOT_UPDATED_MESSAGE, migrations: 'migrations', schema: gitlab.html_link("db/schema.rb")) +end + +if geo_migration_created && !geo_db_schema_updated + warn format(SCHEMA_NOT_UPDATED_MESSAGE, migrations: 'Geo migrations', schema: gitlab.html_link("ee/db/geo/schema.rb")) +end + +db_paths_to_review = database_paths_requiring_review(all_files) + +unless db_paths_to_review.empty? + message 'This merge request adds or changes files that require a ' \ + 'review from the Database team.' + + markdown(<<~MARKDOWN.strip) +## Database Review + +The following files require a review from the Database team: + +* #{db_paths_to_review.map { |path| "`#{path}`" }.join("\n* ")} + +To make sure these changes are reviewed, take the following steps: + +1. Edit your merge request, and add `gl-database` to the list of Group + approvers. +1. Mention `@gl-database` in a separate comment, and explain what needs to be + reviewed by the team. Please don't mention the team until your changes are + ready for review. + MARKDOWN + + unless gitlab.mr_labels.include?('database') + warn 'This merge request is missing the ~database label.' + end +end diff --git a/danger/gemfile/Dangerfile b/danger/gemfile/Dangerfile new file mode 100644 index 00000000000..8ef4a464fe4 --- /dev/null +++ b/danger/gemfile/Dangerfile @@ -0,0 +1,24 @@ +GEMFILE_LOCK_NOT_UPDATED_MESSAGE = <<~MSG.freeze +**%<gemfile>s was updated but %<gemfile_lock>s wasn't updated.** + +Usually, when %<gemfile>s is updated, you should run +``` +bundle install && \ + BUNDLE_GEMFILE=Gemfile.rails5 bundle install +``` + +or + +``` +bundle update <the-added-or-updated-gem> +``` + +and commit the %<gemfile_lock>s changes. +MSG + +gemfile_modified = git.modified_files.include?("Gemfile") +gemfile_lock_modified = git.modified_files.include?("Gemfile.lock") + +if gemfile_modified && !gemfile_lock_modified + warn format(GEMFILE_LOCK_NOT_UPDATED_MESSAGE, gemfile: gitlab.html_link("Gemfile"), gemfile_lock: gitlab.html_link("Gemfile.lock")) +end diff --git a/danger/metadata/Dangerfile b/danger/metadata/Dangerfile new file mode 100644 index 00000000000..3cfaa04e01b --- /dev/null +++ b/danger/metadata/Dangerfile @@ -0,0 +1,25 @@ +# rubocop:disable Style/SignalException + +if gitlab.mr_body.size < 5 + fail "Please provide a proper merge request description." +end + +if gitlab.mr_labels.empty? + fail "Please add labels to this merge request." +end + +unless gitlab.mr_json["assignee"] + warn "This merge request does not have any assignee yet. Setting an assignee clarifies who needs to take action on the merge request at any given time." +end + +has_milestone = !gitlab.mr_json["milestone"].nil? + +unless has_milestone + warn "This merge request does not refer to an existing milestone.", sticky: false +end + +has_pick_into_stable_label = gitlab.mr_labels.find { |label| label.start_with?('Pick into') } + +if gitlab.branch_for_base != "master" && !has_pick_into_stable_label + warn "Most of the time, all merge requests should target `master`. Otherwise, please set the relevant `Pick into X.Y` label." +end diff --git a/danger/specs/Dangerfile b/danger/specs/Dangerfile new file mode 100644 index 00000000000..934ea0beadb --- /dev/null +++ b/danger/specs/Dangerfile @@ -0,0 +1,12 @@ +NO_NEW_SPEC_MESSAGE = <<~MSG.freeze +You've made some app changes, but didn't add any tests. +That's OK as long as you're refactoring existing code, +but please consider adding the ~backstage label in that case. +MSG + +has_app_changes = !git.modified_files.grep(%r{\A(ee/)?(app|lib|db/(geo/)?(post_)?migrate)/}).empty? +has_spec_changes = !git.modified_files.grep(/spec/).empty? + +if has_app_changes && !has_spec_changes + warn NO_NEW_SPEC_MESSAGE, sticky: false +end diff --git a/db/fixtures/development/12_snippets.rb b/db/fixtures/development/12_snippets.rb index 4f3bdba043d..a9f4069a0f8 100644 --- a/db/fixtures/development/12_snippets.rb +++ b/db/fixtures/development/12_snippets.rb @@ -17,7 +17,7 @@ class Member < ActiveRecord::Base scope :guests, -> { where(access_level: GUEST) } scope :reporters, -> { where(access_level: REPORTER) } scope :developers, -> { where(access_level: DEVELOPER) } - scope :masters, -> { where(access_level: MASTER) } + scope :maintainers, -> { where(access_level: MAINTAINER) } scope :owners, -> { where(access_level: OWNER) } delegate :name, :username, :email, to: :user, prefix: true diff --git a/db/fixtures/development/19_environments.rb b/db/fixtures/development/19_environments.rb index 00a14f458d1..3e227928a29 100644 --- a/db/fixtures/development/19_environments.rb +++ b/db/fixtures/development/19_environments.rb @@ -30,14 +30,14 @@ class Gitlab::Seeder::Environments def create_merge_request_review_deployments! @project .merge_requests - .select { |mr| mr.source_branch.match(/\p{Alnum}+/) } + .select { |mr| mr.source_branch.match?(/[a-zA-Z0-9]+/) } .sample(4) .each do |merge_request| next unless merge_request.diff_head_sha create_deployment!( merge_request.source_project, - "review/#{merge_request.source_branch.gsub(/[^a-zA-Z0-9]/, '')}", + "review/#{merge_request.source_branch.gsub(/[^a-zA-Z0-9]+/, '')}", merge_request.source_branch, merge_request.diff_head_sha ) diff --git a/db/migrate/20160705054938_add_protected_branches_push_access.rb b/db/migrate/20160705054938_add_protected_branches_push_access.rb index 97aaaf9d2c8..de3aefcb1fb 100644 --- a/db/migrate/20160705054938_add_protected_branches_push_access.rb +++ b/db/migrate/20160705054938_add_protected_branches_push_access.rb @@ -9,7 +9,7 @@ class AddProtectedBranchesPushAccess < ActiveRecord::Migration create_table :protected_branch_push_access_levels do |t| t.references :protected_branch, index: { name: "index_protected_branch_push_access" }, foreign_key: true, null: false - # Gitlab::Access::MASTER == 40 + # Gitlab::Access::MAINTAINER == 40 t.integer :access_level, default: 40, null: false t.timestamps null: false diff --git a/db/migrate/20160705054952_add_protected_branches_merge_access.rb b/db/migrate/20160705054952_add_protected_branches_merge_access.rb index 51a52a5ac17..9b18a2061b3 100644 --- a/db/migrate/20160705054952_add_protected_branches_merge_access.rb +++ b/db/migrate/20160705054952_add_protected_branches_merge_access.rb @@ -9,7 +9,7 @@ class AddProtectedBranchesMergeAccess < ActiveRecord::Migration create_table :protected_branch_merge_access_levels do |t| t.references :protected_branch, index: { name: "index_protected_branch_merge_access" }, foreign_key: true, null: false - # Gitlab::Access::MASTER == 40 + # Gitlab::Access::MAINTAINER == 40 t.integer :access_level, default: 40, null: false t.timestamps null: false diff --git a/db/migrate/20180608091413_add_group_to_todos.rb b/db/migrate/20180608091413_add_group_to_todos.rb deleted file mode 100644 index af3ee48b29d..00000000000 --- a/db/migrate/20180608091413_add_group_to_todos.rb +++ /dev/null @@ -1,32 +0,0 @@ -class AddGroupToTodos < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - disable_ddl_transaction! - - def up - add_column :todos, :group_id, :integer - add_concurrent_foreign_key :todos, :namespaces, column: :group_id, on_delete: :cascade - add_concurrent_index :todos, :group_id - - change_column_null :todos, :project_id, true - end - - def down - return unless group_id_exists? - - remove_foreign_key :todos, column: :group_id - remove_index :todos, :group_id if index_exists?(:todos, :group_id) - remove_column :todos, :group_id - - execute "DELETE FROM todos WHERE project_id IS NULL" - change_column_null :todos, :project_id, false - end - - private - - def group_id_exists? - column_exists?(:todos, :group_id) - end -end diff --git a/db/migrate/20180704204006_add_hide_third_party_offers_to_application_settings.rb b/db/migrate/20180704204006_add_hide_third_party_offers_to_application_settings.rb new file mode 100644 index 00000000000..6631c5d1b6c --- /dev/null +++ b/db/migrate/20180704204006_add_hide_third_party_offers_to_application_settings.rb @@ -0,0 +1,18 @@ +class AddHideThirdPartyOffersToApplicationSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default(:application_settings, :hide_third_party_offers, + :boolean, + default: false, + allow_null: false) + end + + def down + remove_column(:application_settings, :hide_third_party_offers) + end +end diff --git a/db/post_migrate/20180619121030_enqueue_delete_diff_files_workers.rb b/db/post_migrate/20180619121030_enqueue_delete_diff_files_workers.rb new file mode 100644 index 00000000000..c4d2f5f61a0 --- /dev/null +++ b/db/post_migrate/20180619121030_enqueue_delete_diff_files_workers.rb @@ -0,0 +1,26 @@ +class EnqueueDeleteDiffFilesWorkers < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + SCHEDULER = 'ScheduleDiffFilesDeletion'.freeze + TMP_INDEX = 'tmp_partial_diff_id_with_files_index'.freeze + + disable_ddl_transaction! + + def up + unless index_exists_by_name?(:merge_request_diffs, TMP_INDEX) + add_concurrent_index(:merge_request_diffs, :id, where: "(state NOT IN ('without_files', 'empty'))", name: TMP_INDEX) + end + + BackgroundMigrationWorker.perform_async(SCHEDULER) + + # We don't remove the index since it's going to be used on DeleteDiffFiles + # worker. We should remove it in an upcoming release. + end + + def down + if index_exists_by_name?(:merge_request_diffs, TMP_INDEX) + remove_concurrent_index_by_name(:merge_request_diffs, TMP_INDEX) + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 1898dfc6022..d2aa31fae30 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180702120647) do +ActiveRecord::Schema.define(version: 20180704204006) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -167,6 +167,7 @@ ActiveRecord::Schema.define(version: 20180702120647) do t.boolean "allow_local_requests_from_hooks_and_services", default: false, null: false t.boolean "enforce_terms", default: false t.boolean "mirror_available", default: true, null: false + t.boolean "hide_third_party_offers", default: false, null: false end create_table "audit_events", force: :cascade do |t| @@ -1949,7 +1950,7 @@ ActiveRecord::Schema.define(version: 20180702120647) do create_table "todos", force: :cascade do |t| t.integer "user_id", null: false - t.integer "project_id" + t.integer "project_id", null: false t.integer "target_id" t.string "target_type", null: false t.integer "author_id", null: false @@ -1959,12 +1960,10 @@ ActiveRecord::Schema.define(version: 20180702120647) do t.datetime "updated_at" t.integer "note_id" t.string "commit_id" - t.integer "group_id" end add_index "todos", ["author_id"], name: "index_todos_on_author_id", using: :btree add_index "todos", ["commit_id"], name: "index_todos_on_commit_id", using: :btree - add_index "todos", ["group_id"], name: "index_todos_on_group_id", using: :btree add_index "todos", ["note_id"], name: "index_todos_on_note_id", using: :btree add_index "todos", ["project_id"], name: "index_todos_on_project_id", using: :btree add_index "todos", ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree @@ -2338,7 +2337,6 @@ ActiveRecord::Schema.define(version: 20180702120647) do add_foreign_key "term_agreements", "users", on_delete: :cascade add_foreign_key "timelogs", "issues", name: "fk_timelogs_issues_issue_id", on_delete: :cascade add_foreign_key "timelogs", "merge_requests", name: "fk_timelogs_merge_requests_merge_request_id", on_delete: :cascade - add_foreign_key "todos", "namespaces", column: "group_id", on_delete: :cascade add_foreign_key "todos", "notes", name: "fk_91d1f47b13", on_delete: :cascade add_foreign_key "todos", "projects", name: "fk_45054f9c45", on_delete: :cascade add_foreign_key "todos", "users", column: "author_id", name: "fk_ccf0373936", on_delete: :cascade diff --git a/doc/administration/index.md b/doc/administration/index.md index 922cc45d8c4..88190b2df5f 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -45,6 +45,7 @@ Learn how to install, configure, update, and maintain your GitLab instance. - [Environment variables](environment_variables.md): Supported environment variables that can be used to override their defaults values in order to configure GitLab. - [Plugins](plugins.md): With custom plugins, GitLab administrators can introduce custom integrations without modifying GitLab's source code. - [Enforcing Terms of Service](../user/admin_area/settings/terms.md) +- [Third party offers](../user/admin_area/settings/third_party_offers.md) #### Customizing GitLab's appearance diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md index 10228d027e8..8c55c8c4298 100644 --- a/doc/administration/job_artifacts.md +++ b/doc/administration/job_artifacts.md @@ -88,13 +88,12 @@ _The artifacts are stored by default in ### Using object storage >**Notes:** -- [Introduced][ee-1762] in [GitLab Premium][eep] 9.4. -- Since version 9.5, artifacts are [browsable], when object storage is enabled. - 9.4 lacks this feature. -> Available in [GitLab Premium](https://about.gitlab.com/pricing/) and -[GitLab.com Silver](https://about.gitlab.com/gitlab-com/). -> Since version 10.6, available in [GitLab CE](https://about.gitlab.com/pricing/) -> Since version 11.0, we support direct_upload to S3. +- [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1762) in + [GitLab Premium](https://about.gitlab.com/pricing/) 9.4. +- Since version 9.5, artifacts are [browsable](../user/project/pipelines/job_artifacts.md#browsing-artifacts), + when object storage is enabled. 9.4 lacks this feature. +- Since version 10.6, available in [GitLab Core](https://about.gitlab.com/pricing/) +- Since version 11.0, we support `direct_upload` to S3. If you don't want to use the local disk where GitLab is installed to store the artifacts, you can use an object storage like AWS S3 instead. diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md index c0a281382a5..b3602bc35ab 100644 --- a/doc/administration/pages/index.md +++ b/doc/administration/pages/index.md @@ -259,6 +259,24 @@ verification requirement. Navigate to `Admin area ➔ Settings` and uncheck **Require users to prove ownership of custom domains** in the Pages section. This setting is enabled by default. +## Activate verbose logging for daemon + +Verbose logging was [introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/2533) in +Omnibus GitLab 11.1. + +Follow the steps below to configure verbose logging of GitLab Pages daemon. + +1. By default the daemon only logs with `INFO` level. + + If you wish to make it log events with level `DEBUG` you must configure this in + `/etc/gitlab/gitlab.rb`: + + ```shell + gitlab_pages['log_verbose'] = true + ``` + +1. [Reconfigure GitLab][reconfigure] + ## Change storage path Follow the steps below to change the default path where GitLab Pages' contents diff --git a/doc/api/README.md b/doc/api/README.md index 6267618d3bc..4566319ad45 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -388,7 +388,7 @@ For example, `/` is represented by `%2F`: GET /api/v4/projects/diaspora%2Fdiaspora ``` -## Branches & tags name encoding +## Branches and tags name encoding If your branch or tag contains a `/`, make sure the branch/tag name is URL-encoded. @@ -399,6 +399,36 @@ For example, `/` is represented by `%2F`: GET /api/v4/projects/1/branches/my%2Fbranch/commits ``` +## Encoding API parameters of `array` and `hash` types + +When making an API call with parameters of type `array` and/or `hash`, the parameters may be +specified as shown below. + +### `array` + +`import_sources` is a parameter of type `array`: + +``` +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" \ +-d "import_sources[]=github" \ +-d "import_sources[]=bitbucket" \ +"https://gitlab.example.com/api/v4/some_endpoint +``` + +### `hash` + +`override_params` is a parameter of type `hash`: + +``` +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" \ +--form "namespace=email" \ +--form "path=impapi" \ +--form "file=@/path/to/somefile.txt" +--form "override_params[visibility]=private" \ +--form "override_params[some_other_param]=some_value" \ +https://gitlab.example.com/api/v4/projects/import +``` + ## `id` vs `iid` When you work with the API, you may notice two similar fields in API entities: diff --git a/doc/api/groups.md b/doc/api/groups.md index 53d72509423..11de75039ee 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -210,6 +210,7 @@ Parameters: | --------- | ---- | -------- | ----------- | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) | +| `with_projects` | boolean | no | Include details from projects that belong to the specified group (defaults to `true`). | ```bash curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/4 @@ -361,6 +362,30 @@ Example response: } ``` +When adding the parameter `with_projects=false`, projects will not be returned. + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/4?with_projects=false +``` + +Example response: + +```json +{ + "id": 4, + "name": "Twitter", + "path": "twitter", + "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.", + "visibility": "public", + "avatar_url": null, + "web_url": "https://gitlab.example.com/groups/twitter", + "request_access_enabled": false, + "full_name": "Twitter", + "full_path": "twitter", + "parent_id": null +} +``` + ## New group Creates a new project group. Available only for users who can create groups. diff --git a/doc/api/notes.md b/doc/api/notes.md index d29c5b94915..c271d46688f 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -218,6 +218,7 @@ Parameters: - `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) - `snippet_id` (required) - The ID of a snippet - `body` (required) - The content of a note +- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippet/11/notes?body=note @@ -340,6 +341,7 @@ Parameters: - `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) - `merge_request_iid` (required) - The IID of a merge request - `body` (required) - The content of a note +- `created_at` (optional) - Date time string, ISO 8601 formatted, e.g. 2016-03-11T03:45:40Z ### Modify existing merge request note diff --git a/doc/api/project_import_export.md b/doc/api/project_import_export.md index 085437c801a..83e405141f1 100644 --- a/doc/api/project_import_export.md +++ b/doc/api/project_import_export.md @@ -28,8 +28,11 @@ POST /projects/:id/export | `upload[url]` | string | yes | The URL to upload the project | | `upload[http_method]` | string | no | The HTTP method to upload the exported project. Only `PUT` and `POST` methods allowed. Default is `PUT` | + ```console -curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/export --data "description=FooBar&upload[http_method]=PUT&upload[url]=https://example-bucket.s3.eu-west-3.amazonaws.com/backup?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMBJHN2O62W8IELQ%2F20180312%2Feu-west-3%2Fs3%2Faws4_request&X-Amz-Date=20180312T110328Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=8413facb20ff33a49a147a0b4abcff4c8487cc33ee1f7e450c46e8f695569dbd" +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/export \ + --data "upload[http_method]=PUT" \ + --data-urlencode "upload[url]=https://example-bucket.s3.eu-west-3.amazonaws.com/backup?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMBJHN2O62W8IELQ%2F20180312%2Feu-west-3%2Fs3%2Faws4_request&X-Amz-Date=20180312T110328Z&X-Amz-Expires=900&X-Amz-SignedHeaders=host&X-Amz-Signature=8413facb20ff33a49a147a0b4abcff4c8487cc33ee1f7e450c46e8f695569dbd" ``` ```json @@ -125,6 +128,29 @@ by `@`. For example: curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "path=api-project" --form "file=@/path/to/file" https://gitlab.example.com/api/v4/projects/import ``` +cURL doesn't support posting a file from a remote server. Importing a project from a remote server can be accomplished through something like the following: + +```python +import requests +import urllib +import json +import sys + +s3_file = urllib.urlopen(presigned_url) + +url = 'https://gitlab.example.com/api/v4/projects/import' +files = {'file': s3_file} +data = { + "path": "example-project", + "namespace": "example-group" +} +headers = { + 'Private-Token': "9koXpg98eAheJpvBs5tK" +} + +requests.post(url, headers=headers, data=data, files=files) +``` + ```json { "id": 1, diff --git a/doc/api/projects.md b/doc/api/projects.md index 1e06f6d01f3..a35c2a56992 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -34,7 +34,7 @@ There are currently three options for `merge_method` to choose from: ## List all projects Get a list of all visible projects across GitLab for the authenticated user. -When accessed without authentication, only public projects are returned. +When accessed without authentication, only public projects with "simple" fields are returned. ``` GET /projects @@ -47,7 +47,7 @@ GET /projects | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` | | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Return list of projects matching the search criteria | -| `simple` | boolean | no | Return only the ID, URL, name, and path of each project | +| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. | | `owned` | boolean | no | Limit by projects owned by the current user | | `membership` | boolean | no | Limit by projects that the current user is a member of | | `starred` | boolean | no | Limit by projects starred by the current user | @@ -56,6 +56,41 @@ GET /projects | `with_issues_enabled` | boolean | no | Limit by enabled issues feature | | `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature | +When `simple=true` or the user is unauthenticated this returns something like: + +```json +[ + { + "id": 4, + "description": null, + "default_branch": "master", + "ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git", + "http_url_to_repo": "http://example.com/diaspora/diaspora-client.git", + "web_url": "http://example.com/diaspora/diaspora-client", + "readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md", + "tag_list": [ + "example", + "disapora client" + ], + "name": "Diaspora Client", + "name_with_namespace": "Diaspora / Diaspora Client", + "path": "diaspora-client", + "path_with_namespace": "diaspora/diaspora-client", + "created_at": "2013-09-30T13:46:02Z", + "last_activity_at": "2013-09-30T13:46:02Z", + "forks_count": 0, + "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png", + "star_count": 0, + }, + { + "id": 6, + "description": null, + "default_branch": "master", +... +``` + +When the user is authenticated and `simple` is not set this returns something like: + ```json [ { @@ -235,7 +270,7 @@ GET /users/:user_id/projects | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` | | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Return list of projects matching the search criteria | -| `simple` | boolean | no | Return only the ID, URL, name, and path of each project | +| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. | | `owned` | boolean | no | Limit by projects owned by the current user | | `membership` | boolean | no | Limit by projects that the current user is a member of | | `starred` | boolean | no | Limit by projects starred by the current user | @@ -723,7 +758,7 @@ GET /projects/:id/forks | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` | | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Return list of projects matching the search criteria | -| `simple` | boolean | no | Return only the ID, URL, name, and path of each project | +| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. | | `owned` | boolean | no | Limit by projects owned by the current user | | `membership` | boolean | no | Limit by projects that the current user is a member of | | `starred` | boolean | no | Limit by projects starred by the current user | diff --git a/doc/api/settings.md b/doc/api/settings.md index e6b207d8746..b6f2101fc7b 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -105,7 +105,7 @@ PUT /application/settings | `housekeeping_gc_period` | integer | no | Number of Git pushes after which 'git gc' is run. | | `housekeeping_incremental_repack_period` | integer | no | Number of Git pushes after which an incremental 'git repack' is run. | | `html_emails_enabled` | boolean | no | Enable HTML emails | -| `import_sources` | Array of strings | no | Sources to allow project import from, possible values: "github bitbucket gitlab google_code fogbugz git gitlab_project | +| `import_sources` | Array of strings | no | Sources to allow project import from, possible values: "github bitbucket gitlab google_code fogbugz git gitlab_project manifest | | `koding_enabled` | boolean | no | Enable Koding integration. Default is `false`. | | `koding_url` | string | yes (if `koding_enabled` is `true`) | The Koding instance URL for integration. | | `max_artifacts_size` | integer | no | Maximum artifacts size in MB | diff --git a/doc/api/todos.md b/doc/api/todos.md index 0843e4eedc6..27e623007cc 100644 --- a/doc/api/todos.md +++ b/doc/api/todos.md @@ -18,7 +18,6 @@ Parameters: | `action` | string | no | The action to be filtered. Can be `assigned`, `mentioned`, `build_failed`, `marked`, `approval_required`, `unmergeable` or `directly_addressed`. | | `author_id` | integer | no | The ID of an author | | `project_id` | integer | no | The ID of a project | -| `group_id` | integer | no | The ID of a group | | `state` | string | no | The state of the todo. Can be either `pending` or `done` | | `type` | string | no | The type of a todo. Can be either `Issue` or `MergeRequest` | diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index aa31e172641..811f4d1f07a 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -43,9 +43,9 @@ There's also a collection of repositories with [example projects](https://gitlab - [Using `dpl` as deployment tool](deployment/README.md) - [The `.gitlab-ci.yml` file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml) -## Code quality analysis +## Code Quality analysis -[Analyze code quality with the Code Climate CLI](code_climate.md). +**(Starter)** [Analyze your project's Code Quality](code_quality.md). ## Static Application Security Testing (SAST) diff --git a/doc/ci/examples/code_climate.md b/doc/ci/examples/code_climate.md index 2c8865c6e50..b34637efc8d 100644 --- a/doc/ci/examples/code_climate.md +++ b/doc/ci/examples/code_climate.md @@ -1,49 +1,6 @@ -# Analyze project code quality with Code Climate CLI +--- +redirect_from: 'https://docs.gitlab.com/ee/ci/examples/code_climate.html' +redirect_to: code_quality.md +--- -This example shows how to run [Code Climate CLI][cli] on your code by using -GitLab CI and Docker. - -First, you need GitLab Runner with [docker-in-docker executor][dind]. - -Once you set up the Runner, add a new job to `.gitlab-ci.yml`, called `code_quality`: - -```yaml -code_quality: - image: docker:stable - variables: - DOCKER_DRIVER: overlay2 - allow_failure: true - services: - - docker:stable-dind - script: - - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - - docker run - --env SOURCE_CODE="$PWD" - --volume "$PWD":/code - --volume /var/run/docker.sock:/var/run/docker.sock - "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code - artifacts: - paths: [gl-code-quality-report.json] -``` - -The above example will create a `code_quality` job in your CI/CD pipeline which -will scan your source code for code quality issues. The report will be saved -as an artifact that you can later download and analyze. - -TIP: **Tip:** -Starting with [GitLab Starter][ee] 9.3, this information will -be automatically extracted and shown right in the merge request widget. To do -so, the CI/CD job must be named `code_quality` and the artifact path must be -`gl-code-quality-report.json`. -[Learn more on code quality diffs in merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html). - -CAUTION: **Caution:** -Code Quality was previously using `codeclimate` and `codequality` for job name and -`codeclimate.json` for the artifact name. While these old names -are still maintained they have been deprecated with GitLab 11.0 and may be removed -in next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml` -configuration to reflect that change. - -[cli]: https://github.com/codeclimate/codeclimate -[dind]: ../docker/using_docker_build.md#use-docker-in-docker-executor -[ee]: https://about.gitlab.com/pricing/ +This document was moved to [another location](code_quality.md). diff --git a/doc/ci/examples/code_quality.md b/doc/ci/examples/code_quality.md new file mode 100644 index 00000000000..2a7040ecdeb --- /dev/null +++ b/doc/ci/examples/code_quality.md @@ -0,0 +1,49 @@ +# Analyze your project's Code Quality + +This example shows how to run Code Quality on your code by using GitLab CI/CD +and Docker. + +First, you need GitLab Runner with [docker-in-docker executor][dind]. + +Once you set up the Runner, add a new job to `.gitlab-ci.yml`, called `code_quality`: + +```yaml +code_quality: + image: docker:stable + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:stable-dind + script: + - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') + - docker run + --env SOURCE_CODE="$PWD" + --volume "$PWD":/code + --volume /var/run/docker.sock:/var/run/docker.sock + "registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code + artifacts: + paths: [gl-code-quality-report.json] +``` + +The above example will create a `code_quality` job in your CI/CD pipeline which +will scan your source code for code quality issues. The report will be saved +as an artifact that you can later download and analyze. + +TIP: **Tip:** +Starting with [GitLab Starter][ee] 9.3, this information will +be automatically extracted and shown right in the merge request widget. To do +so, the CI/CD job must be named `code_quality` and the artifact path must be +`gl-code-quality-report.json`. +[Learn more on Code Quality in merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html). + +CAUTION: **Caution:** +Code Quality was previously using `codeclimate` and `codequality` for job name and +`codeclimate.json` for the artifact name. While these old names +are still maintained they have been deprecated with GitLab 11.0 and may be removed +in next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml` +configuration to reflect that change. + +[cli]: https://github.com/codeclimate/codeclimate +[dind]: ../docker/using_docker_build.md#use-docker-in-docker-executor +[ee]: https://about.gitlab.com/pricing/ diff --git a/doc/development/fe_guide/img/vue_arch.png b/doc/development/fe_guide/img/vue_arch.png Binary files differdeleted file mode 100644 index a67706c7c1e..00000000000 --- a/doc/development/fe_guide/img/vue_arch.png +++ /dev/null diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index e31ee087358..f6cbd11042c 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -2,27 +2,24 @@ To get started with Vue, read through [their documentation][vue-docs]. -## Vue architecture +## Examples -All new features built with Vue.js must follow a [Flux architecture][flux]. -The main goal we are trying to achieve is to have only one data flow and only one data entry. -In order to achieve this goal, you can either use [vuex](#vuex) or use the [store pattern][state-management], explained below: +What is described in the following sections can be found in these examples: -Each Vue bundle needs a Store - where we keep all the data -, a Service - that we use to communicate with the server - and a main Vue component. +- web ide: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/ide/stores +- security products: https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/assets/javascripts/vue_shared/security_reports +- registry: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/registry/stores -Think of the Main Vue Component as the entry point of your application. This is the only smart -component that should exist in each Vue feature. -This component is responsible for: -1. Calling the Service to get data from the server -1. Calling the Store to store the data received -1. Mounting all the other components +## Vue architecture -![Vue Architecture](img/vue_arch.png) +All new features built with Vue.js must follow a [Flux architecture][flux]. +The main goal we are trying to achieve is to have only one data flow and only one data entry. +In order to achieve this goal we use [vuex](#vuex). You can also read about this architecture in vue docs about [state management][state-management] and about [one way data flow][one-way-data-flow]. -### Components, Stores and Services +### Components and Store In some features implemented with Vue.js, like the [issue board][issue-boards] or [environments table][environments-table] @@ -33,10 +30,8 @@ new_feature ├── components │ └── component.vue │ └── ... -├── stores +├── store │ └── new_feature_store.js -├── services # only when not using vuex -│ └── new_feature_service.js ├── index.js ``` _For consistency purposes, we recommend you to follow the same structure._ @@ -125,217 +120,6 @@ You can read more about components in Vue.js site, [Component System][component- #### Vuex Check this [page](vuex.md) for more details. -#### Flux like state management -The Store is a class that allows us to manage the state in a single -source of truth. It is not aware of the service or the components. - -The concept we are trying to follow is better explained by Vue documentation -itself, please read this guide: [State Management][state-management] - -### A folder for the Service - -**If you are using Vuex you won't need this step** - -The Service is a class used only to communicate with the server. -It does not store or manipulate any data. It is not aware of the store or the components. -We use [axios][axios] to communicate with the server. -Refer to [axios](axios.md) for more details. - -Axios instance should only be imported in the service file. - -```javascript -import axios from '~/lib/utils/axios_utils'; -``` - -### End Result - -The following example shows an application: - -```javascript -// store.js -export default class Store { - - /** - * This is where we will iniatialize the state of our data. - * Usually in a small SPA you don't need any options when starting the store. - * In that case you do need guarantee it's an Object and it's documented. - * - * @param {Object} options - */ - constructor(options) { - this.options = options; - - // Create a state object to handle all our data in the same place - this.todos = []; - } - - setTodos(todos = []) { - this.todos = todos; - } - - addTodo(todo) { - this.todos.push(todo); - } - - removeTodo(todoID) { - const state = this.todos; - - const newState = state.filter((element) => {element.id !== todoID}); - - this.todos = newState; - } -} - -// service.js -import axios from '~/lib/utils/axios_utils' - -export default class Service { - constructor(options) { - this.todos = axios.create({ - baseURL: endpoint.todosEndpoint - }); - - } - - getTodos() { - return this.todos.get(); - } - - addTodo(todo) { - return this.todos.put(todo); - } -} -// todo_component.vue -<script> -export default { - props: { - data: { - type: Object, - required: true, - }, - }, -}; -</script> -<template> - <div> - <h1> - Title: {{data.title}} - </h1> - <p> - {{data.text}} - </p> - </div> -</template> - -// todos_main_component.vue -<script> -import Store from 'store'; -import Service from 'service'; -import TodoComponent from 'todoComponent'; -export default { - components: { - todo: TodoComponent, - }, - /** - * Although most data belongs in the store, each component it's own state. - * We want to show a loading spinner while we are fetching the todos, this state belong - * in the component. - * - * We need to access the store methods through all methods of our component. - * We need to access the state of our store. - */ - data() { - const store = new Store(); - - return { - isLoading: false, - store: store, - todos: store.todos, - }; - }, - - created() { - this.service = new Service('/todos'); - - this.getTodos(); - }, - - methods: { - getTodos() { - this.isLoading = true; - - this.service - .getTodos() - .then(response => { - this.store.setTodos(response); - this.isLoading = false; - }) - .catch(() => { - this.isLoading = false; - // Show an error - }); - }, - - addTodo(event) { - this.service - .addTodo({ - title: 'New entry', - text: `You clicked on ${event.target.tagName}`, - }) - .then(response => { - this.store.addTodo(response); - }) - .catch(() => { - // Show an error - }); - }, - }, -}; -</script> -<template> - <div class="container"> - <div v-if="isLoading"> - <i - class="fa fa-spin fa-spinner" - aria-hidden="true" /> - </div> - - <div - v-if="!isLoading" - class="js-todo-list"> - <template v-for='todo in todos'> - <todo :data="todo" /> - </template> - - <button - @click="addTodo" - class="js-add-todo"> - Add Todo - </button> - </div> - <div> -</template> - -// index.js -import todoComponent from 'todos_main_component.vue'; - -new Vue({ - el: '.js-todo-app', - components: { - todoComponent, - }, - render: createElement => createElement('todo-component' { - props: { - someProp: [], - } - }), -}); - -``` - -The [issue boards service][issue-boards-service] -is a good example of this pattern. - ## Style guide Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js) @@ -425,7 +209,7 @@ There is a helper in `spec/javascripts/helpers/vue_mount_component_helper.js` th ```javascript import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper.js' +import mountComponent from 'spec/helpers/vue_mount_component_helper' import component from 'component.vue' const Component = Vue.extend(component); @@ -446,6 +230,5 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e [state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch [one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow [vue-test]: https://vuejs.org/v2/guide/unit-testing.html -[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6 [flux]: https://facebook.github.io/flux [axios]: https://github.com/axios/axios diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md index 47396666879..b668c9de6a0 100644 --- a/doc/development/what_requires_downtime.md +++ b/doc/development/what_requires_downtime.md @@ -198,14 +198,14 @@ And that's it, we're done! ## Changing The Schema For Large Tables While `change_column_type_concurrently` and `rename_column_concurrently` can be -used for changing the schema of a table without downtime it doesn't work very +used for changing the schema of a table without downtime, it doesn't work very well for large tables. Because all of the work happens in sequence the migration can take a very long time to complete, preventing a deployment from proceeding. They can also produce a lot of pressure on the database due to it rapidly updating many rows in sequence. To reduce database pressure you should instead use -`change_column_type_using_background_migration` or `rename_column_concurrently` +`change_column_type_using_background_migration` or `rename_column_using_background_migration` when migrating a column in a large table (e.g. `issues`). These methods work similarly to the concurrent counterparts but uses background migration to spread the work / load over a longer time period, without slowing down deployments. diff --git a/doc/install/installation.md b/doc/install/installation.md index 259d8f73a22..4b68090f8d3 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -447,6 +447,15 @@ You can specify a different Git repository by providing it as an extra parameter sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse,https://example.com/gitlab-workhorse.git]" RAILS_ENV=production +### Install gitlab-pages + +GitLab-Pages uses [GNU Make](https://www.gnu.org/software/make/). This step is optional and only needed if you wish to host static sites from within GitLab. The following commands will install GitLab-Pages in `/home/git/gitlab-pages`. For additional setup steps, please consult the [administration guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/administration/pages/source.md) for your version of GitLab as the GitLab Pages daemon can be ran several different ways. + + cd /home/git + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-pages.git + cd gitlab-pages + sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_PAGES_VERSION) + sudo -u git -H make ### Initialize Database and Activate Advanced Features diff --git a/doc/integration/bitbucket.md b/doc/integration/bitbucket.md index 9094d1f2419..2afcb052536 100644 --- a/doc/integration/bitbucket.md +++ b/doc/integration/bitbucket.md @@ -22,8 +22,8 @@ Bitbucket.org. > **Note:** GitLab 8.15 significantly simplified the way to integrate Bitbucket.org with -GitLab. You are encouraged to upgrade your GitLab instance if you haven't done -already. If you're using GitLab 8.14 and below, [use the previous integration +GitLab. You are encouraged to upgrade your GitLab instance if you haven't done so +already. If you're using GitLab 8.14 or below, [use the previous integration docs][bb-old]. To enable the Bitbucket OmniAuth provider you must register your application @@ -64,7 +64,7 @@ you to use. 1. Select **Save**. 1. Select your newly created OAuth consumer and you should now see a Key and - Secret in the list of OAuth customers. Keep this page open as you continue + Secret in the list of OAuth consumers. Keep this page open as you continue the configuration. ![Bitbucket OAuth key](img/bitbucket_oauth_keys.png) @@ -114,8 +114,8 @@ you to use. from the Bitbucket application page. 1. Save the configuration file. -1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you - installed GitLab via Omnibus or from source respectively. +1. For the changes to take effect, [reconfigure GitLab][] if you installed via + Omnibus, or [restart][] if installed from source. On the sign in page there should now be a Bitbucket icon below the regular sign in form. Click the icon to begin the authentication process. Bitbucket will ask @@ -127,12 +127,12 @@ well, the user will be returned to GitLab and will be signed in. Once the above configuration is set up, you can use Bitbucket to sign into GitLab and [start importing your projects][bb-import]. -If you don't want to enable signing in with Bitbucket but just want to import -projects from Bitbucket, you could [disable it in the admin panel](omniauth.md#enable-or-disable-sign-in-with-an-omniauth-provider-without-disabling-import-sources). +If you want to import projects from Bitbucket, but don't want to enable signing in, +you can [disable Sign-Ins in the admin panel](omniauth.md#enable-or-disable-sign-in-with-an-omniauth-provider-without-disabling-import-sources). [init-oauth]: omniauth.md#initial-omniauth-configuration [bb-import]: ../workflow/importing/import_projects_from_bitbucket.md [bb-old]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-14-stable/doc/integration/bitbucket.md [bitbucket-docs]: https://confluence.atlassian.com/bitbucket/use-the-ssh-protocol-with-bitbucket-cloud-221449711.html#UsetheSSHprotocolwithBitbucketCloud-KnownhostorBitbucket%27spublickeyfingerprints -[reconfigure]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure -[restart GitLab]: ../administration/restart_gitlab.md#installations-from-source +[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure +[restart]: ../administration/restart_gitlab.md#installations-from-source diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md index 5554a0c8b78..e1b1912ed47 100644 --- a/doc/raketasks/user_management.md +++ b/doc/raketasks/user_management.md @@ -14,7 +14,7 @@ bundle exec rake gitlab:import:user_to_projects[username@domain.tld] RAILS_ENV=p Notes: -- admin users are added as masters +- admin users are added as maintainers ```bash # omnibus-gitlab diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index bb323705ab3..d04829eaeb8 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -297,7 +297,7 @@ out. In GitLab Starter, differences between the source and target branches are also -[shown in the merge request widget](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html). +[shown in the merge request widget](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html). ### Auto SAST **[ULTIMATE]** diff --git a/doc/update/11.0-to-11.1.md b/doc/update/11.0-to-11.1.md index 306bd417ebf..3f10a7edb8a 100644 --- a/doc/update/11.0-to-11.1.md +++ b/doc/update/11.0-to-11.1.md @@ -187,7 +187,24 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION) sudo -u git -H make ``` -### 10. Update MySQL permissions +### 10. Update gitlab-pages + +#### Only needed if you use GitLab Pages. + +Install and compile gitlab-pages. GitLab-Pages uses +[GNU Make](https://www.gnu.org/software/make/). +If you are not using Linux you may have to run `gmake` instead of +`make` below. + +```bash +cd /home/git/gitlab-pages + +sudo -u git -H git fetch --all --tags --prune +sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_PAGES_VERSION) +sudo -u git -H make +``` + +### 11. Update MySQL permissions If you are using MySQL you need to grant the GitLab user the necessary permissions on the database: @@ -209,7 +226,7 @@ You can make this setting permanent by adding it to your `my.cnf`: log_bin_trust_function_creators=1 ``` -### 11. Update configuration files +### 12. Update configuration files #### New configuration options for `gitlab.yml` @@ -283,7 +300,7 @@ For Ubuntu 16.04.1 LTS: sudo systemctl daemon-reload ``` -### 12. Install libs, migrations, etc. +### 13. Install libs, migrations, etc. ```bash cd /home/git/gitlab @@ -313,14 +330,14 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production **MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md). -### 13. Start application +### 14. Start application ```bash sudo service gitlab start sudo service nginx restart ``` -### 14. Check application status +### 15. Check application status Check if GitLab and its environment are configured correctly: diff --git a/doc/user/admin_area/settings/third_party_offers.md b/doc/user/admin_area/settings/third_party_offers.md new file mode 100644 index 00000000000..177251b52b9 --- /dev/null +++ b/doc/user/admin_area/settings/third_party_offers.md @@ -0,0 +1,6 @@ +# Third party offers + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20379) +> in [GitLab Core](https://about.gitlab.com/pricing/) 11.1 + +The display of third party offers can be controlled in the Admin Area -> Settings page. diff --git a/doc/user/project/clusters/eks_and_gitlab/index.md b/doc/user/project/clusters/eks_and_gitlab/index.md index 2d8fdf0d1da..ec8467da14f 100644 --- a/doc/user/project/clusters/eks_and_gitlab/index.md +++ b/doc/user/project/clusters/eks_and_gitlab/index.md @@ -62,7 +62,7 @@ Click on `Add Kubernetes cluster`, the cluster is now connected to GitLab. At th If you would like to utilize your own CI/CD scripts to deploy to the cluster, you can stop here. -## Disable Role Based-Access Control (RBAC) +## Disable Role-Based Access Control (RBAC) Presently, Auto DevOps and one-click app installs do not support [Kubernetes role-based access control](https://kubernetes.io/docs/reference/access-authn-authz/rbac/). Support is [being worked on](https://gitlab.com/groups/gitlab-org/-/epics/136), but in the interim RBAC must be disabled to utilize for these features. diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index baa6efe50d5..cc1d65e4e6c 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -96,8 +96,9 @@ To add an existing Kubernetes cluster to your project: you can follow the [Kubernetes documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) to create one. You can also view or create service tokens in the - [Kubernetes dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/#config) - (under **Config > Secrets**). + [Kubernetes dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/) + (under **Config > Secrets**). **The account that will issue the service token + must have admin privileges on the cluster.** - **Project namespace** (optional) - You don't have to fill it in; by leaving it blank, GitLab will create one for you. Also: - Each project should have a unique namespace. diff --git a/doc/user/project/import/img/manifest_status.png b/doc/user/project/import/img/manifest_status.png Binary files differnew file mode 100644 index 00000000000..b706116a2ac --- /dev/null +++ b/doc/user/project/import/img/manifest_status.png diff --git a/doc/user/project/import/img/manifest_upload.png b/doc/user/project/import/img/manifest_upload.png Binary files differnew file mode 100644 index 00000000000..d6bf4b157dd --- /dev/null +++ b/doc/user/project/import/img/manifest_upload.png diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md index 72cc58546b7..b55435e5b4f 100644 --- a/doc/user/project/import/index.md +++ b/doc/user/project/import/index.md @@ -11,6 +11,7 @@ 1. [From SVN](svn.md) 1. [From TFS](tfs.md) 1. [From repo by URL](repo_by_url.md) +1. [By uploading a manifest file](manifest.md) In addition to the specific migration documentation above, you can import any Git repository via HTTP from the New Project page. Be aware that if the diff --git a/doc/user/project/import/manifest.md b/doc/user/project/import/manifest.md new file mode 100644 index 00000000000..812ecf05faf --- /dev/null +++ b/doc/user/project/import/manifest.md @@ -0,0 +1,48 @@ +# Import multiple repositories by uploading a manifest file + +GitLab allows you to import all the required git repositories +based a manifest file like the one used by the Android repository. + + +>**Note:** +This feature requires [subgroups](../../group/subgroups/index.md) to be supported by your database. + +You can do it by following next steps: + +1. From your GitLab dashboard click **New project** +1. Switch to the **Import project** tab +1. Click on the **Manifest file** button +1. Provide GitLab with a manifest xml file +1. Select a group you want to import to (you need to create a group first if you don't have one) +1. Click **List available repositories** +1. You will be redirected to the import status page with projects list based on manifest file +1. Check the list and click 'Import all repositories' to start import. + +![Manifest upload](img/manifest_upload.png) + +![Manifest status](img/manifest_status.png) + +### Manifest format + +A manifest must be an XML file. There must be one `remote` tag with `review` attribute +that contains a URL to a git server. Each `project` tag must have `name` and `path` attribute. +GitLab will build URL to the repository by combining URL from `remote` tag with a project name. +A path attribute will be used to represent project path in GitLab system. + +Below is a valid example of manifest file. + +```xml +<manifest> + <remote review="https://android-review.googlesource.com/" /> + + <project path="build/make" name="platform/build" /> + <project path="build/blueprint" name="platform/build/blueprint" /> +</manifest> +``` + +As result next projects will be created: + +| GitLab | Import URL | +|---|---| +| https://gitlab/YOUR_GROUP/build/make | https://android-review.googlesource.com/platform/build | +| https://gitlab/YOUR_GROUP/build/blueprint | https://android-review.googlesource.com/platform/build/blueprint | diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 483a54051d7..86ecf33ed31 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -35,7 +35,7 @@ With **[GitLab Enterprise Edition][ee]**, you can also: - View the deployment process across projects with [Multi-Project Pipeline Graphs](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html#multi-project-pipeline-graphs) **[PREMIUM]** - Request [approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) from your managers **[STARTER]** -- Analyze the impact of your changes with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html) **[STARTER]** +- Analyze the impact of your changes with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html) **[STARTER]** ## Use cases @@ -43,7 +43,7 @@ A. Consider you are a software developer working in a team: 1. You checkout a new branch, and submit your changes through a merge request 1. You gather feedback from your team -1. You work on the implementation optimizing code with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality_diff.html) **[STARTER]** +1. You work on the implementation optimizing code with [Code Quality reports](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html) **[STARTER]** 1. You build and test your changes with GitLab CI/CD 1. You request the approval from your manager 1. Your manager pushes a commit with his final review, [approves the merge request](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html), and set it to [merge when pipeline succeeds](#merge-when-pipeline-succeeds) (Merge Request Approvals are available in GitLab Starter) diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md index dda82352c67..760cd87d4cc 100644 --- a/doc/workflow/todos.md +++ b/doc/workflow/todos.md @@ -109,7 +109,6 @@ There are four kinds of filters you can use on your Todos dashboard. | Filter | Description | | ------- | ----------- | | Project | Filter by project | -| Group | Filter by group | | Author | Filter by the author that triggered the Todo | | Type | Filter by issue or merge request | | Action | Filter by the action that triggered the Todo | diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 40df1e79bc7..66b62d9ee2e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -775,33 +775,28 @@ module API class Todo < Grape::Entity expose :id - expose :project, using: Entities::ProjectIdentity, if: -> (todo, _) { todo.project_id } - expose :group, using: 'API::Entities::NamespaceBasic', if: -> (todo, _) { todo.group_id } + expose :project, using: Entities::BasicProjectDetails expose :author, using: Entities::UserBasic expose :action_name expose :target_type expose :target do |todo, options| - todo_target_class(todo.target_type).represent(todo.target, options) + Entities.const_get(todo.target_type).represent(todo.target, options) end expose :target_url do |todo, options| target_type = todo.target_type.underscore - target_url = "#{todo.parent.class.to_s.underscore}_#{target_type}_url" + target_url = "namespace_project_#{target_type}_url" target_anchor = "note_#{todo.note_id}" if todo.note_id? Gitlab::Routing .url_helpers - .public_send(target_url, todo.parent, todo.target, anchor: target_anchor) # rubocop:disable GitlabSecurity/PublicSend + .public_send(target_url, todo.project.namespace, todo.project, todo.target, anchor: target_anchor) # rubocop:disable GitlabSecurity/PublicSend end expose :body expose :state expose :created_at - - def todo_target_class(target_type) - ::API::Entities.const_get(target_type) - end end class NamespaceBasic < Grape::Entity diff --git a/lib/api/environments.rb b/lib/api/environments.rb index 5c63ec028d9..fa828f43001 100644 --- a/lib/api/environments.rb +++ b/lib/api/environments.rb @@ -89,9 +89,10 @@ module API requires :environment_id, type: Integer, desc: 'The environment ID' end post ':id/environments/:environment_id/stop' do - authorize! :create_deployment, user_project + authorize! :read_environment, user_project environment = user_project.environments.find(params[:environment_id]) + authorize! :stop_environment, environment environment.stop_with_action!(current_user) diff --git a/lib/api/groups.rb b/lib/api/groups.rb index f633dd88d06..797b04df059 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -150,12 +150,13 @@ module API end params do use :with_custom_attributes + optional :with_projects, type: Boolean, default: true, desc: 'Omit project details' end get ":id" do group = find_group!(params[:id]) options = { - with: Entities::GroupDetail, + with: params[:with_projects] ? Entities::GroupDetail : Entities::Group, current_user: current_user } diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb index b4bfb677d72..e2984b08eca 100644 --- a/lib/api/helpers/notes_helpers.rb +++ b/lib/api/helpers/notes_helpers.rb @@ -97,6 +97,8 @@ module API current_user.admin? || parent.owned_by?(current_user) end + opts[:updated_at] = opts[:created_at] if opts[:created_at] + project = parent if parent.is_a?(Project) ::Notes::CreateService.new(project, current_user, opts).execute end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index b83da00502d..8273abe48c9 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -260,7 +260,8 @@ module API :snippets_enabled, :tag_list, :visibility, - :wiki_enabled + :wiki_enabled, + :avatar ] optional :name, type: String, desc: 'The name of the project' optional :default_branch, type: String, desc: 'The default branch of the project' diff --git a/lib/api/runners.rb b/lib/api/runners.rb index 2071c5a62c1..51242341dba 100644 --- a/lib/api/runners.rb +++ b/lib/api/runners.rb @@ -58,7 +58,7 @@ module API optional :access_level, type: String, values: Ci::Runner.access_levels.keys, desc: 'The access_level of the runner' optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this Runner will handle the job' - at_least_one_of :description, :active, :tag_list, :run_untagged, :locked, :access_level + at_least_one_of :description, :active, :tag_list, :run_untagged, :locked, :access_level, :maximum_timeout end put ':id' do runner = get_runner(params.delete(:id)) diff --git a/lib/api/settings.rb b/lib/api/settings.rb index 02ef89f997f..1ca7d23203b 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -25,7 +25,7 @@ module API optional :default_snippet_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default snippet visibility' optional :default_group_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default group visibility' optional :restricted_visibility_levels, type: Array[String], desc: 'Selected levels cannot be used by non-admin users for groups, projects or snippets. If the public level is restricted, user profiles are only visible to logged in users.' - optional :import_sources, type: Array[String], values: %w[github bitbucket gitlab google_code fogbugz git gitlab_project], + optional :import_sources, type: Array[String], values: %w[github bitbucket gitlab google_code fogbugz git gitlab_project manifest], desc: 'Enabled sources for code import during project creation. OmniAuth must be configured for GitHub, Bitbucket, and GitLab.com' optional :disabled_oauth_sign_in_sources, type: Array[String], desc: 'Disable certain OAuth sign-in sources' optional :enabled_git_access_protocol, type: String, values: %w[ssh http nil], desc: 'Allow only the selected protocols to be used for Git access.' diff --git a/lib/declarative_policy.rb b/lib/declarative_policy.rb index 1dd2855063d..dda6cd38dcd 100644 --- a/lib/declarative_policy.rb +++ b/lib/declarative_policy.rb @@ -21,7 +21,17 @@ module DeclarativePolicy cache = opts[:cache] || {} key = Cache.policy_key(user, subject) - cache[key] ||= class_for(subject).new(user, subject, opts) + cache[key] ||= + if Gitlab.rails5? + # to avoid deadlocks in multi-threaded environment when + # autoloading is enabled, we allow concurrent loads, + # https://gitlab.com/gitlab-org/gitlab-ce/issues/48263 + ActiveSupport::Dependencies.interlock.permit_concurrent_loads do + class_for(subject).new(user, subject, opts) + end + else + class_for(subject).new(user, subject, opts) + end end def class_for(subject) diff --git a/lib/gitaly/server.rb b/lib/gitaly/server.rb index 2760211fee8..f95e423ef22 100644 --- a/lib/gitaly/server.rb +++ b/lib/gitaly/server.rb @@ -50,7 +50,7 @@ module Gitaly @info ||= begin Gitlab::GitalyClient::ServerService.new(@storage).info - rescue GRPC::Unavailable, GRPC::GRPC::DeadlineExceeded + rescue GRPC::Unavailable, GRPC::DeadlineExceeded # This will show the server as being out of date Gitaly::ServerInfoResponse.new(git_version: '', server_version: '', storage_statuses: []) end diff --git a/lib/gitlab/access.rb b/lib/gitlab/access.rb index 87e377de4d3..b170145f013 100644 --- a/lib/gitlab/access.rb +++ b/lib/gitlab/access.rb @@ -7,12 +7,14 @@ module Gitlab module Access AccessDeniedError = Class.new(StandardError) - NO_ACCESS = 0 - GUEST = 10 - REPORTER = 20 - DEVELOPER = 30 - MASTER = 40 - OWNER = 50 + NO_ACCESS = 0 + GUEST = 10 + REPORTER = 20 + DEVELOPER = 30 + MAINTAINER = 40 + # @deprecated + MASTER = MAINTAINER + OWNER = 50 # Branch protection settings PROTECTION_NONE = 0 @@ -32,7 +34,7 @@ module Gitlab "Guest" => GUEST, "Reporter" => REPORTER, "Developer" => DEVELOPER, - "Maintainer" => MASTER + "Maintainer" => MAINTAINER } end @@ -44,10 +46,10 @@ module Gitlab def sym_options { - guest: GUEST, - reporter: REPORTER, - developer: DEVELOPER, - master: MASTER + guest: GUEST, + reporter: REPORTER, + developer: DEVELOPER, + maintainer: MAINTAINER } end diff --git a/lib/gitlab/background_migration/delete_diff_files.rb b/lib/gitlab/background_migration/delete_diff_files.rb index 8fb2c334048..664ead1af44 100644 --- a/lib/gitlab/background_migration/delete_diff_files.rb +++ b/lib/gitlab/background_migration/delete_diff_files.rb @@ -4,41 +4,77 @@ module Gitlab module BackgroundMigration class DeleteDiffFiles - def perform(merge_request_diff_id) - merge_request_diff = MergeRequestDiff.find_by(id: merge_request_diff_id) + class MergeRequestDiff < ActiveRecord::Base + self.table_name = 'merge_request_diffs' - return unless merge_request_diff - return unless should_delete_diff_files?(merge_request_diff) + belongs_to :merge_request + has_many :merge_request_diff_files + end - MergeRequestDiff.transaction do - merge_request_diff.update_column(:state, 'without_files') - - # explain (analyze, buffers) when deleting 453 diff files: - # - # Delete on merge_request_diff_files (cost=0.57..8487.35 rows=4846 width=6) (actual time=43.265..43.265 rows=0 loops=1) - # Buffers: shared hit=2043 read=259 dirtied=254 - # -> Index Scan using index_merge_request_diff_files_on_mr_diff_id_and_order on merge_request_diff_files (cost=0.57..8487.35 rows=4846 width=6) (actu - # al time=0.466..26.317 rows=453 loops=1) - # Index Cond: (merge_request_diff_id = 463448) - # Buffers: shared hit=17 read=84 - # Planning time: 0.107 ms - # Execution time: 43.287 ms - # - MergeRequestDiffFile.where(merge_request_diff_id: merge_request_diff.id).delete_all + class MergeRequestDiffFile < ActiveRecord::Base + self.table_name = 'merge_request_diff_files' + end + + DEAD_TUPLES_THRESHOLD = 50_000 + VACUUM_WAIT_TIME = 5.minutes + + def perform(ids) + @ids = ids + + # We should reschedule until deadtuples get in a desirable + # state (e.g. < 50_000). That may take more than one reschedule. + # + if should_wait_deadtuple_vacuum? + reschedule + return end + + prune_diff_files + end + + def should_wait_deadtuple_vacuum? + return false unless Gitlab::Database.postgresql? + + diff_files_dead_tuples_count >= DEAD_TUPLES_THRESHOLD end private - def should_delete_diff_files?(merge_request_diff) - return false if merge_request_diff.state == 'without_files' + def reschedule + BackgroundMigrationWorker.perform_in(VACUUM_WAIT_TIME, self.class.name.demodulize, [@ids]) + end + + def diffs_collection + MergeRequestDiff.where(id: @ids) + end + + def diff_files_dead_tuples_count + dead_tuple = + execute_statement("SELECT n_dead_tup FROM pg_stat_all_tables "\ + "WHERE relname = 'merge_request_diff_files'")[0] - merge_request = merge_request_diff.merge_request + dead_tuple&.fetch('n_dead_tup', 0).to_i + end + + def prune_diff_files + removed = 0 + updated = 0 - return false unless merge_request.state == 'merged' - return false if merge_request_diff.id == merge_request.latest_merge_request_diff_id + MergeRequestDiff.transaction do + updated = diffs_collection.update_all(state: 'without_files') + removed = MergeRequestDiffFile.where(merge_request_diff_id: @ids).delete_all + end + + log_info("Removed #{removed} merge_request_diff_files rows, "\ + "updated #{updated} merge_request_diffs rows") + end + + def execute_statement(sql) + ActiveRecord::Base.connection.execute(sql) + end - true + def log_info(message) + Rails.logger.info("BackgroundMigration::DeleteDiffFiles - #{message}") end end end diff --git a/lib/gitlab/background_migration/schedule_diff_files_deletion.rb b/lib/gitlab/background_migration/schedule_diff_files_deletion.rb new file mode 100644 index 00000000000..609cf19187c --- /dev/null +++ b/lib/gitlab/background_migration/schedule_diff_files_deletion.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true +# rubocop:disable Style/Documentation + +module Gitlab + module BackgroundMigration + class ScheduleDiffFilesDeletion + class MergeRequestDiff < ActiveRecord::Base + self.table_name = 'merge_request_diffs' + + belongs_to :merge_request + + include EachBatch + end + + DIFF_BATCH_SIZE = 5_000 + INTERVAL = 5.minutes + MIGRATION = 'DeleteDiffFiles' + + def perform + diffs = MergeRequestDiff + .from("(#{diffs_collection.to_sql}) merge_request_diffs") + .where('merge_request_diffs.id != merge_request_diffs.latest_merge_request_diff_id') + .select(:id) + + diffs.each_batch(of: DIFF_BATCH_SIZE) do |relation, index| + ids = relation.pluck(:id) + + BackgroundMigrationWorker.perform_in(index * INTERVAL, MIGRATION, [ids]) + end + end + + private + + def diffs_collection + MergeRequestDiff + .joins(:merge_request) + .where("merge_requests.state = 'merged'") + .where('merge_requests.latest_merge_request_diff_id IS NOT NULL') + .where("merge_request_diffs.state NOT IN ('without_files', 'empty')") + .select('merge_requests.latest_merge_request_diff_id, merge_request_diffs.id') + end + end + end +end diff --git a/lib/gitlab/ci/build/artifacts/metadata.rb b/lib/gitlab/ci/build/artifacts/metadata.rb index 0bbd60d8ffe..375d8bc1ff5 100644 --- a/lib/gitlab/ci/build/artifacts/metadata.rb +++ b/lib/gitlab/ci/build/artifacts/metadata.rb @@ -7,14 +7,15 @@ module Gitlab module Artifacts class Metadata ParserError = Class.new(StandardError) + InvalidStreamError = Class.new(StandardError) VERSION_PATTERN = /^[\w\s]+(\d+\.\d+\.\d+)/ INVALID_PATH_PATTERN = %r{(^\.?\.?/)|(/\.?\.?/)} - attr_reader :file, :path, :full_version + attr_reader :stream, :path, :full_version - def initialize(file, path, **opts) - @file, @path, @opts = file, path, opts + def initialize(stream, path, **opts) + @stream, @path, @opts = stream, path, opts @full_version = read_version end @@ -103,7 +104,17 @@ module Gitlab end def gzip(&block) - Zlib::GzipReader.open(@file, &block) + raise InvalidStreamError, "Invalid stream" unless @stream + + # restart gzip reading + @stream.seek(0) + + gz = Zlib::GzipReader.new(@stream) + yield(gz) + rescue Zlib::Error => e + raise InvalidStreamError, e.message + ensure + gz&.finish end end end diff --git a/lib/gitlab/ci/trace/http_io.rb b/lib/gitlab/ci/trace/http_io.rb deleted file mode 100644 index 8788af57a67..00000000000 --- a/lib/gitlab/ci/trace/http_io.rb +++ /dev/null @@ -1,197 +0,0 @@ -## -# This class is compatible with IO class (https://ruby-doc.org/core-2.3.1/IO.html) -# source: https://gitlab.com/snippets/1685610 -module Gitlab - module Ci - class Trace - class HttpIO - BUFFER_SIZE = 128.kilobytes - - InvalidURLError = Class.new(StandardError) - FailedToGetChunkError = Class.new(StandardError) - - attr_reader :uri, :size - attr_reader :tell - attr_reader :chunk, :chunk_range - - alias_method :pos, :tell - - def initialize(url, size) - raise InvalidURLError unless ::Gitlab::UrlSanitizer.valid?(url) - - @uri = URI(url) - @size = size - @tell = 0 - end - - def close - # no-op - end - - def binmode - # no-op - end - - def binmode? - true - end - - def path - nil - end - - def url - @uri.to_s - end - - def seek(pos, where = IO::SEEK_SET) - new_pos = - case where - when IO::SEEK_END - size + pos - when IO::SEEK_SET - pos - when IO::SEEK_CUR - tell + pos - else - -1 - end - - raise 'new position is outside of file' if new_pos < 0 || new_pos > size - - @tell = new_pos - end - - def eof? - tell == size - end - - def each_line - until eof? - line = readline - break if line.nil? - - yield(line) - end - end - - def read(length = nil, outbuf = "") - out = "" - - length ||= size - tell - - until length <= 0 || eof? - data = get_chunk - break if data.empty? - - chunk_bytes = [BUFFER_SIZE - chunk_offset, length].min - chunk_data = data.byteslice(0, chunk_bytes) - - out << chunk_data - @tell += chunk_data.bytesize - length -= chunk_data.bytesize - end - - # If outbuf is passed, we put the output into the buffer. This supports IO.copy_stream functionality - if outbuf - outbuf.slice!(0, outbuf.bytesize) - outbuf << out - end - - out - end - - def readline - out = "" - - until eof? - data = get_chunk - new_line = data.index("\n") - - if !new_line.nil? - out << data[0..new_line] - @tell += new_line + 1 - break - else - out << data - @tell += data.bytesize - end - end - - out - end - - def write(data) - raise NotImplementedError - end - - def truncate(offset) - raise NotImplementedError - end - - def flush - raise NotImplementedError - end - - def present? - true - end - - private - - ## - # The below methods are not implemented in IO class - # - def in_range? - @chunk_range&.include?(tell) - end - - def get_chunk - unless in_range? - response = Net::HTTP.start(uri.hostname, uri.port, proxy_from_env: true, use_ssl: uri.scheme == 'https') do |http| - http.request(request) - end - - raise FailedToGetChunkError unless response.code == '200' || response.code == '206' - - @chunk = response.body.force_encoding(Encoding::BINARY) - @chunk_range = response.content_range - - ## - # Note: If provider does not return content_range, then we set it as we requested - # Provider: minio - # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # Provider: AWS - # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # Provider: GCS - # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 - # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPOK 200 - @chunk_range ||= (chunk_start...(chunk_start + @chunk.bytesize)) - end - - @chunk[chunk_offset..BUFFER_SIZE] - end - - def request - Net::HTTP::Get.new(uri).tap do |request| - request.set_range(chunk_start, BUFFER_SIZE) - end - end - - def chunk_offset - tell % BUFFER_SIZE - end - - def chunk_start - (tell / BUFFER_SIZE) * BUFFER_SIZE - end - - def chunk_end - [chunk_start + BUFFER_SIZE, size].min - end - end - end - end -end diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb index 8c72d00c1f3..ee604e66154 100644 --- a/lib/gitlab/ee_compat_check.rb +++ b/lib/gitlab/ee_compat_check.rb @@ -138,15 +138,23 @@ module Gitlab def ee_branch_presence_check! ee_remotes.keys.each do |remote| - [ce_branch, ee_branch_prefix, ee_branch_suffix].each do |branch| - _, status = step("Fetching #{remote}/#{branch}", %W[git fetch #{remote} #{branch}]) + output, _ = step( + "Searching #{remote}", + %W[git ls-remote #{remote} *#{minimal_ee_branch_name}*]) - if status.zero? - @ee_remote_with_branch = remote - @ee_branch_found = branch - return true - end - end + branches = + output.scan(%r{(?<=refs/heads/|refs/tags/).+}).sort_by(&:size) + + next if branches.empty? + + branch = branches.first + + step("Fetching #{remote}/#{branch}", %W[git fetch #{remote} #{branch}]) + + @ee_remote_with_branch = remote + @ee_branch_found = branch + + return true end puts @@ -271,6 +279,10 @@ module Gitlab @ee_patch_full_path ||= patches_dir.join(ee_patch_name) end + def minimal_ee_branch_name + @minimal_ee_branch_name ||= ce_branch.sub(/(\Ace\-|\-ce\z)/, '') + end + def patch_name_from_branch(branch_name) branch_name.parameterize << '.patch' end diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb index 96fa94d5790..71857bd2d87 100644 --- a/lib/gitlab/git/blob.rb +++ b/lib/gitlab/git/blob.rb @@ -61,17 +61,8 @@ module Gitlab # Keep in mind that this method may allocate a lot of memory. It is up # to the caller to limit the number of blobs and blob_size_limit. # - # Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/798 def batch(repository, blob_references, blob_size_limit: MAX_DATA_DISPLAY_SIZE) - Gitlab::GitalyClient.migrate(:list_blobs_by_sha_path) do |is_enabled| - if is_enabled - repository.gitaly_blob_client.get_blobs(blob_references, blob_size_limit).to_a - else - blob_references.map do |sha, path| - find(repository, sha, path, limit: blob_size_limit) - end - end - end + repository.gitaly_blob_client.get_blobs(blob_references, blob_size_limit).to_a end # Returns an array of Blob instances just with the metadata, that means @@ -84,16 +75,8 @@ module Gitlab # Returns array of Gitlab::Git::Blob # Does not guarantee blob data will be set def batch_lfs_pointers(repository, blob_ids) - repository.gitaly_migrate(:batch_lfs_pointers) do |is_enabled| - if is_enabled - repository.gitaly_blob_client.batch_lfs_pointers(blob_ids.to_a) - else - blob_ids.lazy - .select { |sha| possible_lfs_blob?(repository, sha) } - .map { |sha| rugged_raw(repository, sha, limit: LFS_POINTER_MAX_SIZE) } - .select(&:lfs_pointer?) - .force - end + repository.wrapped_gitaly_errors do + repository.gitaly_blob_client.batch_lfs_pointers(blob_ids.to_a) end end @@ -104,72 +87,6 @@ module Gitlab def size_could_be_lfs?(size) size.between?(LFS_POINTER_MIN_SIZE, LFS_POINTER_MAX_SIZE) end - - private - - # Recursive search of blob id by path - # - # Ex. - # blog/ # oid: 1a - # app/ # oid: 2a - # models/ # oid: 3a - # file.rb # oid: 4a - # - # - # Blob.find_entry_by_path(repo, '1a', 'blog', 'app', 'file.rb') # => '4a' - # - def find_entry_by_path(repository, root_id, *path_parts) - root_tree = repository.lookup(root_id) - - entry = root_tree.find do |entry| - entry[:name] == path_parts[0] - end - - return nil unless entry - - if path_parts.size > 1 - return nil unless entry[:type] == :tree - - path_parts.shift - find_entry_by_path(repository, entry[:oid], *path_parts) - else - [:blob, :commit].include?(entry[:type]) ? entry : nil - end - end - - def submodule_blob(blob_entry, path, sha) - new( - id: blob_entry[:oid], - name: blob_entry[:name], - size: 0, - data: '', - path: path, - commit_id: sha - ) - end - - def rugged_raw(repository, sha, limit:) - blob = repository.lookup(sha) - - return unless blob.is_a?(Rugged::Blob) - - new( - id: blob.oid, - size: blob.size, - data: blob.content(limit), - binary: blob.binary? - ) - end - - # Efficient lookup to determine if object size - # and type make it a possible LFS blob without loading - # blob content into memory with repository.lookup(sha) - def possible_lfs_blob?(repository, sha) - object_header = repository.rugged.read_header(sha) - - object_header[:type] == :blob && - size_could_be_lfs?(object_header[:len]) - end end def initialize(options) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 76404366e8e..d50ac2707f0 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -86,9 +86,6 @@ module Gitlab # Relative path of repo attr_reader :relative_path - # Rugged repo object - attr_reader :rugged - attr_reader :gitlab_projects, :storage, :gl_repository, :relative_path # This initializer method is only used on the client side (gitlab-ce). @@ -112,8 +109,9 @@ module Gitlab [storage, relative_path] == [other.storage, other.relative_path] end + # This method will be removed when Gitaly reaches v1.1. def path - @path ||= File.join( + File.join( Gitlab.config.repositories.storages[@storage].legacy_disk_path, @relative_path ) end @@ -127,8 +125,9 @@ module Gitlab raise Gitlab::Git::CommandError.new(e.message) end + # This method will be removed when Gitaly reaches v1.1. def rugged - @rugged ||= circuit_breaker.perform do + circuit_breaker.perform do Rugged::Repository.new(path, alternates: alternate_object_directories) end rescue Rugged::RepositoryError, Rugged::OSError @@ -627,7 +626,7 @@ module Gitlab def update_branch(branch_name, user:, newrev:, oldrev:) gitaly_migrate(:operation_user_update_branch) do |is_enabled| if is_enabled - gitaly_operations_client.user_update_branch(branch_name, user, newrev, oldrev) + gitaly_operation_client.user_update_branch(branch_name, user, newrev, oldrev) else OperationService.new(user, self).update_branch(branch_name, newrev, oldrev) end @@ -713,12 +712,6 @@ module Gitlab Gitlab::Git.committer_hash(email: user.email, name: user.name) end - def create_commit(params = {}) - params[:message].delete!("\r") - - Rugged::Commit.create(rugged, params) - end - # Delete the specified branch from the repository def delete_branch(branch_name) gitaly_migrate(:delete_branch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| @@ -904,12 +897,8 @@ module Gitlab end def fetch_source_branch!(source_repository, source_branch, local_ref) - Gitlab::GitalyClient.migrate(:fetch_source_branch) do |is_enabled| - if is_enabled - gitaly_repository_client.fetch_source_branch(source_repository, source_branch, local_ref) - else - rugged_fetch_source_branch(source_repository, source_branch, local_ref) - end + wrapped_gitaly_errors do + gitaly_repository_client.fetch_source_branch(source_repository, source_branch, local_ref) end end @@ -1064,12 +1053,8 @@ module Gitlab end def bundle_to_disk(save_path) - gitaly_migrate(:bundle_to_disk) do |is_enabled| - if is_enabled - gitaly_repository_client.create_bundle(save_path) - else - run_git!(%W(bundle create #{save_path} --all)) - end + wrapped_gitaly_errors do + gitaly_repository_client.create_bundle(save_path) end true @@ -1766,6 +1751,12 @@ module Gitlab def sha_from_ref(ref) rev_parse_target(ref).oid end + + def create_commit(params = {}) + params[:message].delete!("\r") + + Rugged::Commit.create(rugged, params) + end end end end diff --git a/lib/gitlab/git/rev_list.rb b/lib/gitlab/git/rev_list.rb index 5fdad077eea..2ba68343aa5 100644 --- a/lib/gitlab/git/rev_list.rb +++ b/lib/gitlab/git/rev_list.rb @@ -12,35 +12,12 @@ module Gitlab end # This method returns an array of new commit references - def new_refs - repository.rev_list(including: newrev, excluding: :all).split("\n") - end - - # Finds newly added objects - # Returns an array of shas + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/1233 # - # Can skip objects which do not have a path using required_path: true - # This skips commit objects and root trees, which might not be needed when - # looking for blobs - # - # When given a block it will yield objects as a lazy enumerator so - # the caller can limit work done instead of processing megabytes of data - def new_objects(options: [], require_path: nil, not_in: nil, &lazy_block) - opts = { - including: newrev, - options: options, - excluding: not_in.nil? ? :all : not_in, - require_path: require_path - } - - get_objects(opts, &lazy_block) - end - - def all_objects(options: [], require_path: nil, &lazy_block) - get_objects(including: :all, - options: options, - require_path: require_path, - &lazy_block) + def new_refs + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rev_list(including: newrev, excluding: :all).split("\n") + end end private diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index db7c29be94b..35808149b90 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -2,6 +2,8 @@ # class return an instance of `GitlabAccessStatus` module Gitlab class GitAccess + include Gitlab::Utils::StrongMemoize + UnauthorizedError = Class.new(StandardError) NotFoundError = Class.new(StandardError) ProjectCreationError = Class.new(StandardError) @@ -26,7 +28,7 @@ module Gitlab PUSH_COMMANDS = %w{ git-receive-pack }.freeze ALL_COMMANDS = DOWNLOAD_COMMANDS + PUSH_COMMANDS - attr_reader :actor, :project, :protocol, :authentication_abilities, :namespace_path, :project_path, :redirected_path, :auth_result_type + attr_reader :actor, :project, :protocol, :authentication_abilities, :namespace_path, :project_path, :redirected_path, :auth_result_type, :changes def initialize(actor, project, protocol, authentication_abilities:, namespace_path: nil, project_path: nil, redirected_path: nil, auth_result_type: nil) @actor = actor @@ -40,6 +42,8 @@ module Gitlab end def check(cmd, changes) + @changes = changes + check_protocol! check_valid_actor! check_active_user! @@ -58,7 +62,7 @@ module Gitlab when *DOWNLOAD_COMMANDS check_download_access! when *PUSH_COMMANDS - check_push_access!(changes) + check_push_access! end true @@ -218,7 +222,7 @@ module Gitlab end end - def check_push_access!(changes) + def check_push_access! if project.repository_read_only? raise UnauthorizedError, ERROR_MESSAGES[:read_only] end @@ -235,17 +239,15 @@ module Gitlab return if changes.blank? # Allow access this is needed for EE. - check_change_access!(changes) + check_change_access! end - def check_change_access!(changes) + def check_change_access! # If there are worktrees with a HEAD pointing to a non-existent object, # calls to `git rev-list --all` will fail in git 2.15+. This should also # clear stale lock files. project.repository.clean_stale_repository_files - changes_list = Gitlab::ChangesList.new(changes) - # Iterate over all changes to find if user allowed all of them to be applied changes_list.each.with_index do |change, index| first_change = index == 0 @@ -321,6 +323,10 @@ module Gitlab protected + def changes_list + @changes_list ||= Gitlab::ChangesList.new(changes) + end + def user return @user if defined?(@user) diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb index b1a01b185e6..aa7e03301f5 100644 --- a/lib/gitlab/gitaly_client/conflicts_service.rb +++ b/lib/gitlab/gitaly_client/conflicts_service.rb @@ -25,10 +25,12 @@ module Gitlab def conflicts? list_conflict_files.any? - rescue GRPC::FailedPrecondition - # The server raises this exception when it encounters ConflictSideMissing, which - # means a conflict exists but its `theirs` or `ours` data is nil due to a non-existent - # file in one of the trees. + rescue GRPC::FailedPrecondition, GRPC::Unknown + # The server raises FailedPrecondition when it encounters + # ConflictSideMissing, which means a conflict exists but its `theirs` or + # `ours` data is nil due to a non-existent file in one of the trees. + # + # GRPC::Unknown comes from Rugged::ReferenceError and Rugged::OdbError. true end diff --git a/lib/gitlab/gitaly_client/server_service.rb b/lib/gitlab/gitaly_client/server_service.rb index 2e1076d1f66..ad898278353 100644 --- a/lib/gitlab/gitaly_client/server_service.rb +++ b/lib/gitlab/gitaly_client/server_service.rb @@ -9,7 +9,7 @@ module Gitlab end def info - GitalyClient.call(@storage, :server_service, :server_info, Gitaly::ServerInfoRequest.new) + GitalyClient.call(@storage, :server_service, :server_info, Gitaly::ServerInfoRequest.new, timeout: GitalyClient.fast_timeout) end end end diff --git a/lib/gitlab/http_io.rb b/lib/gitlab/http_io.rb new file mode 100644 index 00000000000..ce24817db54 --- /dev/null +++ b/lib/gitlab/http_io.rb @@ -0,0 +1,193 @@ +## +# This class is compatible with IO class (https://ruby-doc.org/core-2.3.1/IO.html) +# source: https://gitlab.com/snippets/1685610 +module Gitlab + class HttpIO + BUFFER_SIZE = 128.kilobytes + + InvalidURLError = Class.new(StandardError) + FailedToGetChunkError = Class.new(StandardError) + + attr_reader :uri, :size + attr_reader :tell + attr_reader :chunk, :chunk_range + + alias_method :pos, :tell + + def initialize(url, size) + raise InvalidURLError unless ::Gitlab::UrlSanitizer.valid?(url) + + @uri = URI(url) + @size = size + @tell = 0 + end + + def close + # no-op + end + + def binmode + # no-op + end + + def binmode? + true + end + + def path + nil + end + + def url + @uri.to_s + end + + def seek(pos, where = IO::SEEK_SET) + new_pos = + case where + when IO::SEEK_END + size + pos + when IO::SEEK_SET + pos + when IO::SEEK_CUR + tell + pos + else + -1 + end + + raise 'new position is outside of file' if new_pos < 0 || new_pos > size + + @tell = new_pos + end + + def eof? + tell == size + end + + def each_line + until eof? + line = readline + break if line.nil? + + yield(line) + end + end + + def read(length = nil, outbuf = "") + out = "" + + length ||= size - tell + + until length <= 0 || eof? + data = get_chunk + break if data.empty? + + chunk_bytes = [BUFFER_SIZE - chunk_offset, length].min + chunk_data = data.byteslice(0, chunk_bytes) + + out << chunk_data + @tell += chunk_data.bytesize + length -= chunk_data.bytesize + end + + # If outbuf is passed, we put the output into the buffer. This supports IO.copy_stream functionality + if outbuf + outbuf.slice!(0, outbuf.bytesize) + outbuf << out + end + + out + end + + def readline + out = "" + + until eof? + data = get_chunk + new_line = data.index("\n") + + if !new_line.nil? + out << data[0..new_line] + @tell += new_line + 1 + break + else + out << data + @tell += data.bytesize + end + end + + out + end + + def write(data) + raise NotImplementedError + end + + def truncate(offset) + raise NotImplementedError + end + + def flush + raise NotImplementedError + end + + def present? + true + end + + private + + ## + # The below methods are not implemented in IO class + # + def in_range? + @chunk_range&.include?(tell) + end + + def get_chunk + unless in_range? + response = Net::HTTP.start(uri.hostname, uri.port, proxy_from_env: true, use_ssl: uri.scheme == 'https') do |http| + http.request(request) + end + + raise FailedToGetChunkError unless response.code == '200' || response.code == '206' + + @chunk = response.body.force_encoding(Encoding::BINARY) + @chunk_range = response.content_range + + ## + # Note: If provider does not return content_range, then we set it as we requested + # Provider: minio + # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # Provider: AWS + # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # Provider: GCS + # - When the file size is larger than requested Content-range, the Content-range is included in responces with Net::HTTPPartialContent 206 + # - When the file size is smaller than requested Content-range, the Content-range is included in responces with Net::HTTPOK 200 + @chunk_range ||= (chunk_start...(chunk_start + @chunk.bytesize)) + end + + @chunk[chunk_offset..BUFFER_SIZE] + end + + def request + Net::HTTP::Get.new(uri).tap do |request| + request.set_range(chunk_start, BUFFER_SIZE) + end + end + + def chunk_offset + tell % BUFFER_SIZE + end + + def chunk_start + (tell / BUFFER_SIZE) * BUFFER_SIZE + end + + def chunk_end + [chunk_start + BUFFER_SIZE, size].min + end + end +end diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb index 8b8e48aac76..ac827cbe1ca 100644 --- a/lib/gitlab/import_export/members_mapper.rb +++ b/lib/gitlab/import_export/members_mapper.rb @@ -47,7 +47,7 @@ module Gitlab def ensure_default_member! @project.project_members.destroy_all - ProjectMember.create!(user: @user, access_level: ProjectMember::MASTER, source_id: @project.id, importing: true) + ProjectMember.create!(user: @user, access_level: ProjectMember::MAINTAINER, source_id: @project.id, importing: true) end def add_team_member(member, existing_user = nil) diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb index 10289af6b25..f901d1fdb5a 100644 --- a/lib/gitlab/import_sources.rb +++ b/lib/gitlab/import_sources.rb @@ -17,7 +17,8 @@ module Gitlab ImportSource.new('fogbugz', 'FogBugz', Gitlab::FogbugzImport::Importer), ImportSource.new('git', 'Repo by URL', nil), ImportSource.new('gitlab_project', 'GitLab export', Gitlab::ImportExport::Importer), - ImportSource.new('gitea', 'Gitea', Gitlab::LegacyGithubImport::Importer) + ImportSource.new('gitea', 'Gitea', Gitlab::LegacyGithubImport::Importer), + ImportSource.new('manifest', 'Manifest file', nil) ].freeze class << self diff --git a/lib/gitlab/kubernetes.rb b/lib/gitlab/kubernetes.rb index da43bd0af4b..15c5ece2350 100644 --- a/lib/gitlab/kubernetes.rb +++ b/lib/gitlab/kubernetes.rb @@ -1,6 +1,10 @@ module Gitlab # Helper methods to do with Kubernetes network services & resources module Kubernetes + def self.build_header_hash + Hash.new { |h, k| h[k] = [] } + end + # This is the comand that is run to start a terminal session. Kubernetes # expects `command=foo&command=bar, not `command[]=foo&command[]=bar` EXEC_COMMAND = URI.encode_www_form( @@ -37,13 +41,14 @@ module Gitlab selectors: { pod: pod_name, container: container["name"] }, url: container_exec_url(api_url, namespace, pod_name, container["name"]), subprotocols: ['channel.k8s.io'], - headers: Hash.new { |h, k| h[k] = [] }, + headers: ::Gitlab::Kubernetes.build_header_hash, created_at: created_at } end end def add_terminal_auth(terminal, token:, max_session_time:, ca_pem: nil) + terminal[:headers] ||= ::Gitlab::Kubernetes.build_header_hash terminal[:headers]['Authorization'] << "Bearer #{token}" terminal[:max_session_time] = max_session_time terminal[:ca_pem] = ca_pem if ca_pem.present? diff --git a/lib/gitlab/manifest_import/manifest.rb b/lib/gitlab/manifest_import/manifest.rb new file mode 100644 index 00000000000..4d6034fb956 --- /dev/null +++ b/lib/gitlab/manifest_import/manifest.rb @@ -0,0 +1,81 @@ +# Class to parse manifest file and build a list of repositories for import +# +# <manifest> +# <remote review="https://android-review.googlesource.com/" /> +# <project path="platform-common" name="platform" /> +# <project path="platform/art" name="platform/art" /> +# <project path="platform/device" name="platform/device" /> +# </manifest> +# +# 1. Project path must be uniq and can't be part of other project path. +# For example, you can't have projects with 'foo' and 'foo/bar' paths. +# 2. Remote must be present with review attribute so GitLab knows +# where to fetch source code +module Gitlab + module ManifestImport + class Manifest + attr_reader :parsed_xml, :errors + + def initialize(file) + @parsed_xml = Nokogiri::XML(file) { |config| config.strict } + @errors = [] + rescue Nokogiri::XML::SyntaxError + @errors = ['The uploaded file is not a valid XML file.'] + end + + def projects + raw_projects.each_with_index.map do |project, i| + { + id: i, + name: project['name'], + path: project['path'], + url: repository_url(project['name']) + } + end + end + + def valid? + return false if @errors.any? + + unless validate_remote + @errors << 'Make sure a <remote> tag is present and is valid.' + end + + unless validate_projects + @errors << 'Make sure every <project> tag has name and path attributes.' + end + + @errors.empty? + end + + private + + def validate_remote + remote.present? && URI.parse(remote).host + rescue URI::Error + false + end + + def validate_projects + raw_projects.all? do |project| + project['name'] && project['path'] + end + end + + def repository_url(name) + URI.join(remote, name).to_s + end + + def remote + return @remote if defined?(@remote) + + remote_tag = parsed_xml.css('manifest > remote').first + @remote = remote_tag['review'] if remote_tag + end + + def raw_projects + @raw_projects ||= parsed_xml.css('manifest > project') + end + end + end +end diff --git a/lib/gitlab/manifest_import/project_creator.rb b/lib/gitlab/manifest_import/project_creator.rb new file mode 100644 index 00000000000..b5967c93735 --- /dev/null +++ b/lib/gitlab/manifest_import/project_creator.rb @@ -0,0 +1,41 @@ +module Gitlab + module ManifestImport + class ProjectCreator + attr_reader :repository, :destination, :current_user + + def initialize(repository, destination, current_user) + @repository = repository + @destination = destination + @current_user = current_user + end + + def execute + group_full_path, _, project_path = repository[:path].rpartition('/') + group_full_path = File.join(destination.full_path, group_full_path) if destination + group = create_group_with_parents(group_full_path) + + params = { + import_url: repository[:url], + import_type: 'manifest', + namespace_id: group.id, + path: project_path, + name: project_path, + visibility_level: destination.visibility_level + } + + Projects::CreateService.new(current_user, params).execute + end + + private + + def create_group_with_parents(full_path) + params = { + group_path: full_path, + visibility_level: destination.visibility_level + } + + Groups::NestedCreateService.new(current_user, params).execute + end + end + end +end diff --git a/lib/gitlab/project_authorizations/with_nested_groups.rb b/lib/gitlab/project_authorizations/with_nested_groups.rb index 15b8beacf60..e3da1634fa5 100644 --- a/lib/gitlab/project_authorizations/with_nested_groups.rb +++ b/lib/gitlab/project_authorizations/with_nested_groups.rb @@ -24,7 +24,7 @@ module Gitlab user.projects.select_for_project_authorization, # The personal projects of the user. - user.personal_projects.select_as_master_for_project_authorization, + user.personal_projects.select_as_maintainer_for_project_authorization, # Projects that belong directly to any of the groups the user has # access to. diff --git a/lib/gitlab/project_authorizations/without_nested_groups.rb b/lib/gitlab/project_authorizations/without_nested_groups.rb index ad87540e6c2..7d0c00c7f36 100644 --- a/lib/gitlab/project_authorizations/without_nested_groups.rb +++ b/lib/gitlab/project_authorizations/without_nested_groups.rb @@ -15,7 +15,7 @@ module Gitlab user.projects.select_for_project_authorization, # Personal projects - user.personal_projects.select_as_master_for_project_authorization, + user.personal_projects.select_as_maintainer_for_project_authorization, # Projects of groups the user is a member of user.groups_projects.select_for_project_authorization, diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index e222541992a..a17cd27e82d 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -92,21 +92,13 @@ module Gitlab # Ex. # import_repository("nfs-file06", "gitlab/gitlab-ci", "https://gitlab.com/gitlab-org/gitlab-test.git") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/874 def import_repository(storage, name, url) if url.start_with?('.', '/') raise Error.new("don't use disk paths with import_repository: #{url.inspect}") end relative_path = "#{name}.git" - cmd = gitaly_migrate(:import_repository, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled| - if is_enabled - GitalyGitlabProjects.new(storage, relative_path) - else - # The timeout ensures the subprocess won't hang forever - gitlab_projects(storage, relative_path) - end - end + cmd = GitalyGitlabProjects.new(storage, relative_path) success = cmd.import_project(url, git_timeout) raise Error, cmd.output unless success @@ -126,12 +118,8 @@ module Gitlab # fetch_remote(my_repo, "upstream") # def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true) - gitaly_migrate(:fetch_remote) do |is_enabled| - if is_enabled - repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout, prune: prune) - else - local_fetch_remote(repository.storage, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune) - end + wrapped_gitaly_errors do + repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout, prune: prune) end end @@ -389,28 +377,6 @@ module Gitlab ) end - def local_fetch_remote(storage_name, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true) - vars = { force: forced, tags: !no_tags, prune: prune } - - if ssh_auth&.ssh_import? - if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present? - vars[:ssh_key] = ssh_auth.ssh_private_key - end - - if ssh_auth.ssh_known_hosts.present? - vars[:known_hosts] = ssh_auth.ssh_known_hosts - end - end - - cmd = gitlab_projects(storage_name, repository_relative_path) - - success = cmd.fetch_remote(remote, git_timeout, vars) - - raise Error, cmd.output unless success - - success - end - def gitlab_shell_fast_execute(cmd) output, status = gitlab_shell_fast_execute_helper(cmd) @@ -440,10 +406,6 @@ module Gitlab Gitlab.config.gitlab_shell.git_timeout end - def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block) - wrapped_gitaly_errors { Gitlab::GitalyClient.migrate(method, status: status, &block) } - end - def wrapped_gitaly_errors yield rescue GRPC::NotFound, GRPC::BadStatus => e diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb index 59331c827af..de8b6ec69ce 100644 --- a/lib/gitlab/url_sanitizer.rb +++ b/lib/gitlab/url_sanitizer.rb @@ -58,7 +58,7 @@ module Gitlab if raw_credentials.present? url.sub!("#{raw_credentials}@", '') - user, password = raw_credentials.split(':') + user, _, password = raw_credentials.partition(':') @credentials ||= { user: user.presence, password: password.presence } end diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 55c899912f9..a9629a92a50 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -98,16 +98,12 @@ module Gitlab end def send_git_patch(repository, diff_refs) - params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_send_git_patch, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) - { - 'GitalyServer' => gitaly_server_hash(repository), - 'RawPatchRequest' => Gitaly::RawPatchRequest.new( - gitaly_diff_or_patch_hash(repository, diff_refs) - ).to_json - } - else - workhorse_diff_or_patch_hash(repository, diff_refs) - end + params = { + 'GitalyServer' => gitaly_server_hash(repository), + 'RawPatchRequest' => Gitaly::RawPatchRequest.new( + gitaly_diff_or_patch_hash(repository, diff_refs) + ).to_json + } [ SEND_DATA_HEADER, @@ -220,14 +216,6 @@ module Gitlab } end - def workhorse_diff_or_patch_hash(repository, diff_refs) - { - 'RepoPath' => repository.path_to_repo, - 'ShaFrom' => diff_refs.base_sha, - 'ShaTo' => diff_refs.head_sha - } - end - def gitaly_diff_or_patch_hash(repository, diff_refs) { repository: repository.gitaly_repository, diff --git a/lib/tasks/gettext.rake b/lib/tasks/gettext.rake index 6df7fe81437..f431352b61e 100644 --- a/lib/tasks/gettext.rake +++ b/lib/tasks/gettext.rake @@ -20,16 +20,22 @@ namespace :gettext do end task :regenerate do + pot_file = 'locale/gitlab.pot' # Remove all translated files, this speeds up finding FileUtils.rm Dir['locale/**/gitlab.*'] # remove the `pot` file to ensure it's completely regenerated - FileUtils.rm_f 'locale/gitlab.pot' + FileUtils.rm_f pot_file Rake::Task['gettext:find'].invoke # leave only the required changes. `git checkout -- locale/*/gitlab.po` + # Remove timestamps from the pot file + pot_content = File.read pot_file + pot_content.gsub!(/^"POT?\-(?:Creation|Revision)\-Date\:.*\n/, '') + File.write pot_file, pot_content + puts <<~MSG All done. Please commit the changes to `locale/gitlab.pot`. diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake index 83dd870fa31..26cbf0740b6 100644 --- a/lib/tasks/gitlab/bulk_add_permission.rake +++ b/lib/tasks/gitlab/bulk_add_permission.rake @@ -1,6 +1,6 @@ namespace :gitlab do namespace :import do - desc "GitLab | Add all users to all projects (admin users are added as masters)" + desc "GitLab | Add all users to all projects (admin users are added as maintainers)" task all_users_to_all_projects: :environment do |t, args| user_ids = User.where(admin: false).pluck(:id) admin_ids = User.where(admin: true).pluck(:id) @@ -10,7 +10,7 @@ namespace :gitlab do ProjectMember.add_users_to_projects(project_ids, user_ids, ProjectMember::DEVELOPER) puts "Importing #{admin_ids.size} admins into #{project_ids.size} projects" - ProjectMember.add_users_to_projects(project_ids, admin_ids, ProjectMember::MASTER) + ProjectMember.add_users_to_projects(project_ids, admin_ids, ProjectMember::MAINTAINER) end desc "GitLab | Add a specific user to all projects (as a developer)" diff --git a/locale/gitlab.pot b/locale/gitlab.pot index ca488053a1f..eb3433b3ba2 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -8,8 +8,6 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-07-09 08:28+0200\n" -"PO-Revision-Date: 2018-07-09 08:28+0200\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "Language: \n" @@ -128,7 +126,7 @@ msgstr "" msgid "%{unstaged} unstaged and %{staged} staged changes" msgstr "" -msgid "(checkout the %{link} for information on how to install it)." +msgid "(check out the %{link} for information on how to install it)." msgstr "" msgid "+ %{moreCount} more" @@ -465,6 +463,9 @@ msgstr "" msgid "An error occurred. Please try again." msgstr "" +msgid "Any" +msgstr "" + msgid "Appearance" msgstr "" @@ -687,6 +688,9 @@ msgstr "" msgid "Below are examples of regex for existing tools:" msgstr "" +msgid "Below you will find all the groups that are public." +msgstr "" + msgid "Boards" msgstr "" @@ -977,6 +981,9 @@ msgstr "" msgid "Choose file..." msgstr "" +msgid "Choose the top-level group for your repository imports." +msgstr "" + msgid "Choose which repositories you want to import." msgstr "" @@ -1644,6 +1651,9 @@ msgstr "" msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." msgstr "" +msgid "Control the display of third party offers." +msgstr "" + msgid "Copy URL to clipboard" msgstr "" @@ -1719,6 +1729,9 @@ msgstr "" msgid "Create new file" msgstr "" +msgid "Create new file or directory" +msgstr "" + msgid "Create new label" msgstr "" @@ -1976,6 +1989,12 @@ msgstr "" msgid "Discard draft" msgstr "" +msgid "Discover projects, groups and snippets. Share your projects with others" +msgstr "" + +msgid "Dismiss" +msgstr "" + msgid "Dismiss Cycle Analytics introduction box" msgstr "" @@ -2099,9 +2118,18 @@ msgstr "" msgid "Environments|An error occurred while making the request." msgstr "" +msgid "Environments|An error occurred while stopping the environment, please try again" +msgstr "" + +msgid "Environments|Are you sure you want to stop this environment?" +msgstr "" + msgid "Environments|Commit" msgstr "" +msgid "Environments|Deploy to..." +msgstr "" + msgid "Environments|Deployment" msgstr "" @@ -2114,27 +2142,39 @@ msgstr "" msgid "Environments|Job" msgstr "" +msgid "Environments|Learn more about stopping environments" +msgstr "" + msgid "Environments|New environment" msgstr "" msgid "Environments|No deployments yet" msgstr "" -msgid "Environments|Open" +msgid "Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action” being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file." +msgstr "" + +msgid "Environments|Open live environment" msgstr "" -msgid "Environments|Re-deploy" +msgid "Environments|Re-deploy to environment" msgstr "" msgid "Environments|Read more about environments" msgstr "" -msgid "Environments|Rollback" +msgid "Environments|Rollback environment" msgstr "" msgid "Environments|Show all" msgstr "" +msgid "Environments|Stop" +msgstr "" + +msgid "Environments|Stop environment" +msgstr "" + msgid "Environments|Updated" msgstr "" @@ -2225,6 +2265,12 @@ msgstr "" msgid "Expand sidebar" msgstr "" +msgid "Explore GitLab" +msgstr "" + +msgid "Explore Groups" +msgstr "" + msgid "Explore groups" msgstr "" @@ -2404,6 +2450,9 @@ msgstr "" msgid "Graph" msgstr "" +msgid "Group" +msgstr "" + msgid "Group CI/CD settings" msgstr "" @@ -2440,6 +2489,9 @@ msgstr "" msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name}" msgstr "" +msgid "Groups" +msgstr "" + msgid "Groups can also be nested by creating %{subgroup_docs_link_start}subgroups%{subgroup_docs_link_end}." msgstr "" @@ -2604,6 +2656,9 @@ msgstr "" msgid "Import in progress" msgstr "" +msgid "Import multiple repositories by uploading a manifest file." +msgstr "" + msgid "Import repositories from GitHub" msgstr "" @@ -2813,6 +2868,9 @@ msgstr "" msgid "List" msgstr "" +msgid "List available repositories" +msgstr "" + msgid "List your GitHub repositories" msgstr "" @@ -2852,6 +2910,12 @@ msgstr "" msgid "Manage project labels" msgstr "" +msgid "Manifest" +msgstr "" + +msgid "Manifest file import" +msgstr "" + msgid "Mar" msgstr "" @@ -3002,6 +3066,9 @@ msgstr "" msgid "More information is available|here" msgstr "" +msgid "Most stars" +msgstr "" + msgid "Move" msgstr "" @@ -3130,6 +3197,9 @@ msgstr "" msgid "No messages were logged" msgstr "" +msgid "No public groups" +msgstr "" + msgid "No repository" msgstr "" @@ -3799,9 +3869,6 @@ msgstr "" msgid "Quick actions can be used in the issues description and comment boxes." msgstr "" -msgid "Re-deploy" -msgstr "" - msgid "Read more" msgstr "" @@ -3871,6 +3938,9 @@ msgstr "" msgid "Repository Settings" msgstr "" +msgid "Repository URL" +msgstr "" + msgid "Repository maintenance" msgstr "" @@ -3936,9 +4006,6 @@ msgstr "" msgid "Reviewing (merge request !%{mergeRequestId})" msgstr "" -msgid "Rollback" -msgstr "" - msgid "Runner token" msgstr "" @@ -4600,6 +4667,9 @@ msgstr "" msgid "They can be managed using the %{link}." msgstr "" +msgid "Third party offers" +msgstr "" + msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area." msgstr "" @@ -4916,6 +4986,9 @@ msgstr "" msgid "Track time with quick actions" msgstr "" +msgid "Trending" +msgstr "" + msgid "Trigger this manual action" msgstr "" @@ -5056,6 +5129,9 @@ msgstr "" msgid "Visibility and access controls" msgstr "" +msgid "Visibility:" +msgstr "" + msgid "VisibilityLevel|Internal" msgstr "" @@ -5260,6 +5336,9 @@ msgstr "" msgid "You can also test your .gitlab-ci.yml in the %{linkStart}Lint%{linkEnd}" msgstr "" +msgid "You can easily contribute to them by requesting to join these groups." +msgstr "" + msgid "You can easily install a Runner on a Kubernetes cluster. %{link_to_help_page}" msgstr "" diff --git a/qa/README.md b/qa/README.md index a4b4398645e..be4cf89ebbc 100644 --- a/qa/README.md +++ b/qa/README.md @@ -55,7 +55,7 @@ Since the arguments would be passed to `rspec`, you could use all `rspec` options there. For example, passing `--backtrace` and also line number: ``` -bin/qa Test::Instance http://localhost qa/specs/features/login/standard_spec.rb:3 --backtrace +bin/qa Test::Instance http://localhost qa/specs/features/project/create_spec.rb:3 --backtrace ``` ### Overriding the authenticated user @@ -41,13 +41,17 @@ module QA autoload :Project, 'qa/factory/resource/project' autoload :MergeRequest, 'qa/factory/resource/merge_request' autoload :ProjectImportedFromGithub, 'qa/factory/resource/project_imported_from_github' + autoload :MergeRequestFromFork, 'qa/factory/resource/merge_request_from_fork' autoload :DeployKey, 'qa/factory/resource/deploy_key' autoload :Branch, 'qa/factory/resource/branch' autoload :SecretVariable, 'qa/factory/resource/secret_variable' autoload :Runner, 'qa/factory/resource/runner' autoload :PersonalAccessToken, 'qa/factory/resource/personal_access_token' autoload :KubernetesCluster, 'qa/factory/resource/kubernetes_cluster' + autoload :User, 'qa/factory/resource/user' + autoload :ProjectMilestone, 'qa/factory/resource/project_milestone' autoload :Wiki, 'qa/factory/resource/wiki' + autoload :Fork, 'qa/factory/resource/fork' end module Repository @@ -106,6 +110,7 @@ module QA module Main autoload :Login, 'qa/page/main/login' autoload :OAuth, 'qa/page/main/oauth' + autoload :SignUp, 'qa/page/main/sign_up' end module Settings @@ -166,6 +171,15 @@ module QA autoload :Index, 'qa/page/project/issue/index' end + module Fork + autoload :New, 'qa/page/project/fork/new' + end + + module Milestone + autoload :New, 'qa/page/project/milestone/new' + autoload :Index, 'qa/page/project/milestone/index' + end + module Operations module Kubernetes autoload :Index, 'qa/page/project/operations/kubernetes/index' @@ -194,6 +208,10 @@ module QA autoload :Sidebar, 'qa/page/issuable/sidebar' end + module Layout + autoload :Banner, 'qa/page/layout/banner' + end + module MergeRequest autoload :New, 'qa/page/merge_request/new' autoload :Show, 'qa/page/merge_request/show' diff --git a/qa/qa/factory/repository/project_push.rb b/qa/qa/factory/repository/project_push.rb index 48674c08a8d..4f78098d348 100644 --- a/qa/qa/factory/repository/project_push.rb +++ b/qa/qa/factory/repository/project_push.rb @@ -11,6 +11,8 @@ module QA factory.output end + product(:project) { |factory| factory.project } + def initialize @file_name = 'file.txt' @file_content = '# This is test project' diff --git a/qa/qa/factory/repository/push.rb b/qa/qa/factory/repository/push.rb index 4f97e65b091..5b7ebf6c41f 100644 --- a/qa/qa/factory/repository/push.rb +++ b/qa/qa/factory/repository/push.rb @@ -5,7 +5,8 @@ module QA module Repository class Push < Factory::Base attr_accessor :file_name, :file_content, :commit_message, - :branch_name, :new_branch, :output, :repository_uri + :branch_name, :new_branch, :output, :repository_uri, + :user attr_writer :remote_branch @@ -31,9 +32,20 @@ module QA def fabricate! Git::Repository.perform do |repository| repository.uri = repository_uri + repository.use_default_credentials + username = 'GitLab QA' + email = 'root@gitlab.com' + + if user + repository.username = user.username + repository.password = user.password + username = user.name + email = user.email + end + repository.clone - repository.configure_identity('GitLab QA', 'root@gitlab.com') + repository.configure_identity(username, email) if new_branch repository.checkout_new_branch(branch_name) diff --git a/qa/qa/factory/resource/fork.rb b/qa/qa/factory/resource/fork.rb new file mode 100644 index 00000000000..1d0c76a3d30 --- /dev/null +++ b/qa/qa/factory/resource/fork.rb @@ -0,0 +1,24 @@ +module QA + module Factory + module Resource + class Fork < Factory::Base + dependency Factory::Repository::ProjectPush, as: :push + + dependency Factory::Resource::User, as: :user + + product(:user) { |factory| factory.user } + + def fabricate! + push.project.visit! + Page::Project::Show.act { fork_project } + + Page::Project::Fork::New.perform do |fork_new| + fork_new.choose_namespace(user.name) + end + + Page::Layout::Banner.act { has_notice?('The project was successfully forked.') } + end + end + end + end +end diff --git a/qa/qa/factory/resource/merge_request.rb b/qa/qa/factory/resource/merge_request.rb index 24d3597d993..ddb62bd0a68 100644 --- a/qa/qa/factory/resource/merge_request.rb +++ b/qa/qa/factory/resource/merge_request.rb @@ -7,7 +7,10 @@ module QA attr_accessor :title, :description, :source_branch, - :target_branch + :target_branch, + :assignee, + :milestone, + :labels product :project do |factory| factory.project @@ -41,16 +44,18 @@ module QA @description = 'This is a test merge request' @source_branch = "qa-test-feature-#{SecureRandom.hex(8)}" @target_branch = "master" + @assignee = nil + @milestone = nil + @labels = [] end def fabricate! project.visit! - Page::Project::Show.act { new_merge_request } - Page::MergeRequest::New.perform do |page| page.fill_title(@title) page.fill_description(@description) + page.choose_milestone(@milestone) if @milestone page.create_merge_request end end diff --git a/qa/qa/factory/resource/merge_request_from_fork.rb b/qa/qa/factory/resource/merge_request_from_fork.rb new file mode 100644 index 00000000000..6caaf65f673 --- /dev/null +++ b/qa/qa/factory/resource/merge_request_from_fork.rb @@ -0,0 +1,24 @@ +module QA + module Factory + module Resource + class MergeRequestFromFork < MergeRequest + attr_accessor :fork_branch + + dependency Factory::Resource::Fork, as: :fork + + dependency Factory::Repository::ProjectPush, as: :push do |push, factory| + push.project = factory.fork + push.branch_name = factory.fork_branch + push.file_name = 'file2.txt' + push.user = factory.fork.user + end + + def fabricate! + fork.visit! + Page::Project::Show.act { new_merge_request } + Page::MergeRequest::New.act { create_merge_request } + end + end + end + end +end diff --git a/qa/qa/factory/resource/project.rb b/qa/qa/factory/resource/project.rb index 7bc64c6ae5d..7fff22b5468 100644 --- a/qa/qa/factory/resource/project.rb +++ b/qa/qa/factory/resource/project.rb @@ -37,6 +37,7 @@ module QA page.choose_test_namespace page.choose_name(@name) page.add_description(@description) + page.set_visibility('Public') page.create_new_project end end diff --git a/qa/qa/factory/resource/project_milestone.rb b/qa/qa/factory/resource/project_milestone.rb new file mode 100644 index 00000000000..47a5e74204f --- /dev/null +++ b/qa/qa/factory/resource/project_milestone.rb @@ -0,0 +1,36 @@ +module QA + module Factory + module Resource + class ProjectMilestone < Factory::Base + attr_accessor :description + attr_reader :title + + dependency Factory::Resource::Project, as: :project + + product(:title) { |factory| factory.title } + + def title=(title) + @title = "#{title}-#{SecureRandom.hex(4)}" + @description = 'A milestone' + end + + def fabricate! + project.visit! + + Page::Menu::Side.act do + click_issues + click_milestones + end + + Page::Project::Milestone::Index.act { click_new_milestone } + + Page::Project::Milestone::New.perform do |milestone_new| + milestone_new.set_title(@title) + milestone_new.set_description(@description) + milestone_new.create_new_milestone + end + end + end + end + end +end diff --git a/qa/qa/factory/resource/user.rb b/qa/qa/factory/resource/user.rb new file mode 100644 index 00000000000..e08df9e0cd0 --- /dev/null +++ b/qa/qa/factory/resource/user.rb @@ -0,0 +1,34 @@ +require 'securerandom' + +module QA + module Factory + module Resource + class User < Factory::Base + attr_accessor :name, :username, :email, :password + + def initialize + @name = "name-#{SecureRandom.hex(8)}" + @username = "username-#{SecureRandom.hex(8)}" + @email = "mail#{SecureRandom.hex(8)}@mail.com" + @password = 'password' + end + + product(:name) { |factory| factory.name } + + product(:username) { |factory| factory.username } + + product(:email) { |factory| factory.email } + + product(:password) { |factory| factory.password } + + def fabricate! + Page::Menu::Main.act { sign_out } + Page::Main::Login.act { switch_to_register_tab } + Page::Main::SignUp.perform do |page| + page.sign_up!(name: name, username: username, email: email, password: password) + end + end + end + end + end +end diff --git a/qa/qa/page/issuable/sidebar.rb b/qa/qa/page/issuable/sidebar.rb index dec2ce1eab3..f207264e24f 100644 --- a/qa/qa/page/issuable/sidebar.rb +++ b/qa/qa/page/issuable/sidebar.rb @@ -4,6 +4,7 @@ module QA class Sidebar < Page::Base view 'app/views/shared/issuable/_sidebar.html.haml' do element :labels_block, ".issuable-show-labels" + element :milestones_block, '.block.milestone' end def has_label?(label) @@ -11,6 +12,12 @@ module QA !!find('span', text: label) end end + + def has_milestone?(milestone) + page.within('.block.milestone') do + !!find("[href*='/milestones/']", text: milestone) + end + end end end end diff --git a/qa/qa/page/layout/banner.rb b/qa/qa/page/layout/banner.rb new file mode 100644 index 00000000000..e7654bdafc9 --- /dev/null +++ b/qa/qa/page/layout/banner.rb @@ -0,0 +1,17 @@ +module QA + module Page + module Layout + class Banner < Page::Base + view 'app/views/layouts/header/_read_only_banner.html.haml' do + element :flash_notice, ".flash-notice" + end + + def has_notice?(message) + page.within('.flash-notice') do + !!find('span', text: message) + end + end + end + end + end +end diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb index 26c99efc53d..6cdfbd1c125 100644 --- a/qa/qa/page/main/login.rb +++ b/qa/qa/page/main/login.rb @@ -25,19 +25,24 @@ module QA element :standard_tab, "link_to 'Standard'" end + view 'app/views/devise/shared/_tabs_normal.html.haml' do + element :sign_in_tab, /nav-link.*login-pane.*Sign in/ + element :register_tab, /nav-link.*register-pane.*Register/ + end + def initialize # The login page is usually the entry point for all the scenarios so # we need to wait for the instance to start. That said, in some cases # we are already logged-in so we check both cases here. wait(max: 500) do page.has_css?('.login-page') || - Page::Menu::Main.act { has_personal_area? } + Page::Menu::Main.act { has_personal_area?(wait: 0) } end end def sign_in_using_credentials # Don't try to log-in if we're already logged-in - return if Page::Menu::Main.act { has_personal_area? } + return if Page::Menu::Main.act { has_personal_area?(wait: 0) } using_wait_time 0 do set_initial_password_if_present @@ -48,12 +53,22 @@ module QA sign_in_using_gitlab_credentials end end + + Page::Menu::Main.act { has_personal_area? } end def self.path '/users/sign_in' end + def switch_to_sign_in_tab + click_on 'Sign in' + end + + def switch_to_register_tab + click_on 'Register' + end + private def sign_in_using_ldap_credentials diff --git a/qa/qa/page/main/sign_up.rb b/qa/qa/page/main/sign_up.rb new file mode 100644 index 00000000000..9a834e94b81 --- /dev/null +++ b/qa/qa/page/main/sign_up.rb @@ -0,0 +1,27 @@ +module QA + module Page + module Main + class SignUp < Page::Base + view 'app/views/devise/shared/_signup_box.html.haml' do + element :name, 'text_field :name' + element :username, 'text_field :username' + element :email_field, 'email_field :email' + element :email_confirmation, 'email_field :email_confirmation' + element :password, 'password_field :password' + element :register_button, 'submit "Register"' + end + + def sign_up!(name:, username:, email:, password:) + fill_in :new_user_name, with: name + fill_in :new_user_username, with: username + fill_in :new_user_email, with: email + fill_in :new_user_email_confirmation, with: email + fill_in :new_user_password, with: password + click_button 'Register' + + Page::Menu::Main.act { has_personal_area? } + end + end + end + end +end diff --git a/qa/qa/page/menu/main.rb b/qa/qa/page/menu/main.rb index aef5c9f9c82..36e7285f7b7 100644 --- a/qa/qa/page/menu/main.rb +++ b/qa/qa/page/menu/main.rb @@ -60,9 +60,9 @@ module QA end end - def has_personal_area? + def has_personal_area?(wait: Capybara.default_max_wait_time) # No need to wait, either we're logged-in, or not. - using_wait_time(0) { page.has_selector?('.qa-user-avatar') } + using_wait_time(wait) { page.has_selector?('.qa-user-avatar') } end private diff --git a/qa/qa/page/menu/side.rb b/qa/qa/page/menu/side.rb index 333d871c51a..c14a835c2c9 100644 --- a/qa/qa/page/menu/side.rb +++ b/qa/qa/page/menu/side.rb @@ -16,6 +16,7 @@ module QA element :operations_section, "class: 'shortcuts-operations'" element :activity_link, "title: 'Activity'" element :wiki_link_text, "Wiki" + element :milestones_link end view 'app/assets/javascripts/fly_out_nav.js' do @@ -70,6 +71,12 @@ module QA end end + def click_milestones + within_sidebar do + click_element :milestones_link + end + end + def click_wiki within_sidebar do click_link('Wiki') diff --git a/qa/qa/page/merge_request/new.rb b/qa/qa/page/merge_request/new.rb index ec94ff4ac98..83cc4bbbace 100644 --- a/qa/qa/page/merge_request/new.rb +++ b/qa/qa/page/merge_request/new.rb @@ -10,10 +10,18 @@ module QA element :issuable_form_title end + view 'app/views/shared/issuable/form/_metadata.html.haml' do + element :issuable_milestone_dropdown + end + view 'app/views/shared/form_elements/_description.html.haml' do element :issuable_form_description end + view 'app/views/shared/issuable/_milestone_dropdown.html.haml' do + element :issuable_dropdown_menu_milestone + end + def create_merge_request click_element :issuable_create_button end @@ -25,6 +33,13 @@ module QA def fill_description(description) fill_element :issuable_form_description, description end + + def choose_milestone(milestone) + click_element :issuable_milestone_dropdown + within_element(:issuable_dropdown_menu_milestone) do + click_on milestone.title + end + end end end end diff --git a/qa/qa/page/project/fork/new.rb b/qa/qa/page/project/fork/new.rb new file mode 100644 index 00000000000..ed92df956bf --- /dev/null +++ b/qa/qa/page/project/fork/new.rb @@ -0,0 +1,17 @@ +module QA + module Page + module Project + module Fork + class New < Page::Base + view 'app/views/projects/forks/_fork_button.html.haml' do + element :namespace, 'link_to project_forks_path' + end + + def choose_namespace(namespace = Runtime::Namespace.path) + click_on namespace + end + end + end + end + end +end diff --git a/qa/qa/page/project/milestone/index.rb b/qa/qa/page/project/milestone/index.rb new file mode 100644 index 00000000000..a1519c9ef1c --- /dev/null +++ b/qa/qa/page/project/milestone/index.rb @@ -0,0 +1,17 @@ +module QA + module Page + module Project + module Milestone + class Index < Page::Base + view 'app/views/projects/milestones/index.html.haml' do + element :new_project_milestone + end + + def click_new_milestone + click_element :new_project_milestone + end + end + end + end + end +end diff --git a/qa/qa/page/project/milestone/new.rb b/qa/qa/page/project/milestone/new.rb new file mode 100644 index 00000000000..992ef89004b --- /dev/null +++ b/qa/qa/page/project/milestone/new.rb @@ -0,0 +1,27 @@ +module QA + module Page + module Project + module Milestone + class New < Page::Base + view 'app/views/projects/milestones/_form.html.haml' do + element :milestone_create_button + element :milestone_title + element :milestone_description + end + + def set_title(title) + fill_element :milestone_title, title + end + + def set_description(description) + fill_element :milestone_description, description + end + + def create_new_milestone + click_element :milestone_create_button + end + end + end + end + end +end diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb index 7976e96d43b..9e812fa7c74 100644 --- a/qa/qa/page/project/new.rb +++ b/qa/qa/page/project/new.rb @@ -14,6 +14,7 @@ module QA element :project_path, 'text_field :path' element :project_description, 'text_area :description' element :project_create_button, "submit 'Create project'" + element :visibility_radios, 'visibility_level:' end view 'app/views/projects/_import_project_pane.html.haml' do @@ -42,6 +43,10 @@ module QA click_on 'Create project' end + def set_visibility(visibility) + choose visibility + end + def go_to_github_import click_link 'GitHub' end diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb index 0bd031e96b5..e572ae12132 100644 --- a/qa/qa/page/project/settings/protected_branches.rb +++ b/qa/qa/page/project/settings/protected_branches.rb @@ -44,6 +44,9 @@ module QA click_allow(:push, 'Developers + Maintainers') end + # @deprecated + alias_method :allow_devs_and_masters_to_push, :allow_devs_and_maintainers_to_push + def allow_no_one_to_merge click_allow(:merge, 'No one') end @@ -52,6 +55,9 @@ module QA click_allow(:merge, 'Developers + Maintainers') end + # @deprecated + alias_method :allow_devs_and_masters_to_merge, :allow_devs_and_maintainers_to_merge + def protect_branch click_on 'Protect' end diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb index 1dcdb59490a..88861d5772d 100644 --- a/qa/qa/page/project/show.rb +++ b/qa/qa/page/project/show.rb @@ -22,6 +22,11 @@ module QA element :branches_dropdown end + view 'app/views/projects/buttons/_fork.html.haml' do + element :fork_label, "%span= s_('GoToYourFork|Fork')" + element :fork_link, "link_to new_project_fork_path(@project)" + end + view 'app/views/projects/_files.html.haml' do element :tree_holder, '.tree-holder' end @@ -61,6 +66,10 @@ module QA click_link 'New issue' end + + def fork_project + click_on 'Fork' + end end end end diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb index cee381f3379..877864fb40c 100644 --- a/qa/qa/runtime/browser.rb +++ b/qa/qa/runtime/browser.rb @@ -85,6 +85,10 @@ module QA driver.browser.save_screenshot(path) end + Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| + File.join(QA::Runtime::Namespace.name, example.file_path.sub('./qa/specs/features/', '')) + end + Capybara.configure do |config| config.default_driver = :chrome config.javascript_driver = :chrome diff --git a/qa/qa/runtime/namespace.rb b/qa/qa/runtime/namespace.rb index ccfa8b44db3..28f17d1160b 100644 --- a/qa/qa/runtime/namespace.rb +++ b/qa/qa/runtime/namespace.rb @@ -8,7 +8,7 @@ module QA end def name - 'qa-test-' + time.strftime('%d-%m-%Y-%H-%M-%S') + "qa-test-#{time.strftime('%Y-%m-%d-%Y-%H-%M-%S')}" end def path diff --git a/qa/qa/specs/features/login/standard_spec.rb b/qa/qa/specs/features/login/standard_spec.rb deleted file mode 100644 index 254f47cf217..00000000000 --- a/qa/qa/specs/features/login/standard_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -module QA - describe 'standard user login', :core do - it 'user logs in using credentials' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } - - # TODO, since `Signed in successfully` message was removed - # this is the only way to tell if user is signed in correctly. - # - Page::Menu::Main.perform do |menu| - expect(menu).to have_personal_area - end - end - end -end diff --git a/qa/qa/specs/features/merge_request/create_spec.rb b/qa/qa/specs/features/merge_request/create_spec.rb index 18e8c1f35af..36d7efb02e1 100644 --- a/qa/qa/specs/features/merge_request/create_spec.rb +++ b/qa/qa/specs/features/merge_request/create_spec.rb @@ -4,14 +4,29 @@ module QA Runtime::Browser.visit(:gitlab, Page::Main::Login) Page::Main::Login.act { sign_in_using_credentials } + current_project = Factory::Resource::Project.fabricate! do |project| + project.name = 'project-with-merge-request-and-milestone' + end + + current_milestone = Factory::Resource::ProjectMilestone.fabricate! do |milestone| + milestone.title = 'unique-milestone' + milestone.project = current_project + end + Factory::Resource::MergeRequest.fabricate! do |merge_request| - merge_request.title = 'This is a merge request' - merge_request.description = 'Great feature' + merge_request.title = 'This is a merge request with a milestone' + merge_request.description = 'Great feature with milestone' + merge_request.project = current_project + merge_request.milestone = current_milestone end - expect(page).to have_content('This is a merge request') - expect(page).to have_content('Great feature') + expect(page).to have_content('This is a merge request with a milestone') + expect(page).to have_content('Great feature with milestone') expect(page).to have_content(/Opened [\w\s]+ ago/) + + Page::Issuable::Sidebar.perform do |sidebar| + expect(sidebar).to have_milestone(current_milestone.title) + end end end end diff --git a/qa/qa/specs/features/project/fork_project_spec.rb b/qa/qa/specs/features/project/fork_project_spec.rb new file mode 100644 index 00000000000..8ad0120305a --- /dev/null +++ b/qa/qa/specs/features/project/fork_project_spec.rb @@ -0,0 +1,23 @@ +module QA + describe 'Project fork', :core do + it 'can submit merge requests to upstream master' do + Runtime::Browser.visit(:gitlab, Page::Main::Login) + Page::Main::Login.act { sign_in_using_credentials } + + merge_request = Factory::Resource::MergeRequestFromFork.fabricate! do |merge_request| + merge_request.fork_branch = 'feature-branch' + end + + Page::Menu::Main.act { sign_out } + Page::Main::Login.act do + switch_to_sign_in_tab + sign_in_using_credentials + end + + merge_request.visit! + Page::MergeRequest::Show.act { merge! } + + expect(page).to have_content('The changes were merged') + end + end +end diff --git a/qa/qa/specs/features/repository/protected_branches_spec.rb b/qa/qa/specs/features/repository/protected_branches_spec.rb index 29ea2e69ec7..4e593a69aae 100644 --- a/qa/qa/specs/features/repository/protected_branches_spec.rb +++ b/qa/qa/specs/features/repository/protected_branches_spec.rb @@ -13,15 +13,11 @@ module QA Page::Main::Login.act { sign_in_using_credentials } end - after do |example| + after do # We need to clear localStorage because we're using it for the dropdown, # and capybara doesn't do this for us. # https://github.com/teamcapybara/capybara/issues/1702 Capybara.execute_script 'localStorage.clear()' - - # In order to help diagnose a false failure - # https://gitlab.com/gitlab-org/gitlab-ce/issues/48241 - log_push_output if example.exception end context 'when developers and maintainers are allowed to push to a protected branch' do @@ -31,9 +27,9 @@ module QA expect(protected_branch.name).to have_content(branch_name) expect(protected_branch.push_allowance).to have_content('Developers + Maintainers') - @push = push_new_file(branch_name) + push = push_new_file(branch_name) - expect(@push.output).to match(/remote: To create a merge request for protected-branch, visit/) + expect(push.output).to match(/remote: To create a merge request for protected-branch, visit/) end end @@ -41,11 +37,11 @@ module QA it 'user without push rights fails to push to the protected branch' do create_protected_branch(allow_to_push: false) - @push = push_new_file(branch_name) + push = push_new_file(branch_name) - expect(@push.output) + expect(push.output) .to match(/remote\: GitLab\: You are not allowed to push code to protected branches on this project/) - expect(@push.output) + expect(push.output) .to match(/\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/) end end @@ -69,13 +65,5 @@ module QA resource.new_branch = false end end - - def log_push_output - if defined?(@push) - filename = File.join('tmp', "push-output-#{project.name}") - puts "Exception detected. Push output will be saved to #{filename}" - IO.binwrite(filename, @push.output) - end - end end end diff --git a/spec/bin/changelog_spec.rb b/spec/bin/changelog_spec.rb index f278043028f..9dc4edf97d1 100644 --- a/spec/bin/changelog_spec.rb +++ b/spec/bin/changelog_spec.rb @@ -3,6 +3,20 @@ require 'spec_helper' load File.expand_path('../../bin/changelog', __dir__) describe 'bin/changelog' do + let(:options) { OpenStruct.new(title: 'Test title', type: 'fixed', dry_run: true) } + + describe ChangelogEntry do + it 'truncates the file path' do + entry = described_class.new(options) + + allow(entry).to receive(:ee?).and_return(false) + allow(entry).to receive(:branch_name).and_return('long-branch-' * 100) + + file_path = entry.send(:file_path) + expect(file_path.length).to eq(140) + end + end + describe ChangelogOptionParser do describe '.parse' do it 'parses --amend' do diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index fb6d82d7de3..2c59d1929a1 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -228,12 +228,12 @@ describe AutocompleteController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end context 'authorized projects' do before do - authorized_project.add_master(user) + authorized_project.add_maintainer(user) end describe 'GET #projects with project ID' do @@ -253,8 +253,8 @@ describe AutocompleteController do context 'authorized projects and search' do before do - authorized_project.add_master(user) - authorized_search_project.add_master(user) + authorized_project.add_maintainer(user) + authorized_search_project.add_maintainer(user) end describe 'GET #projects with project ID and search' do @@ -277,9 +277,9 @@ describe AutocompleteController do authorized_project2 = create(:project) authorized_project3 = create(:project) - authorized_project.add_master(user) - authorized_project2.add_master(user) - authorized_project3.add_master(user) + authorized_project.add_maintainer(user) + authorized_project2.add_maintainer(user) + authorized_project3.add_maintainer(user) stub_const 'MoveToProjectFinder::PAGE_SIZE', 2 end @@ -301,9 +301,9 @@ describe AutocompleteController do authorized_project2 = create(:project) authorized_project3 = create(:project) - authorized_project.add_master(user) - authorized_project2.add_master(user) - authorized_project3.add_master(user) + authorized_project.add_maintainer(user) + authorized_project2.add_maintainer(user) + authorized_project3.add_maintainer(user) end describe 'GET #projects with project ID and offset_id' do diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index e47ff8661a2..ce7762691c9 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -13,7 +13,7 @@ describe Boards::IssuesController do let!(:list2) { create(:list, board: board, label: development, position: 1) } before do - project.add_master(user) + project.add_maintainer(user) project.add_guest(guest) end diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb index 57ccbf1d6b5..80631d2efb0 100644 --- a/spec/controllers/boards/lists_controller_spec.rb +++ b/spec/controllers/boards/lists_controller_spec.rb @@ -7,7 +7,7 @@ describe Boards::ListsController do let(:guest) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) project.add_guest(guest) end diff --git a/spec/controllers/dashboard/groups_controller_spec.rb b/spec/controllers/dashboard/groups_controller_spec.rb index 7f2eaf95165..9068c1a792e 100644 --- a/spec/controllers/dashboard/groups_controller_spec.rb +++ b/spec/controllers/dashboard/groups_controller_spec.rb @@ -28,8 +28,8 @@ describe Dashboard::GroupsController do let!(:other_group) { create(:group, name: 'other') } before do - top_level_result.add_master(user) - top_level_a.add_master(user) + top_level_result.add_maintainer(user) + top_level_a.add_maintainer(user) end it 'renders only groups the user is a member of when searching hierarchy correctly' do diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb index 60547db82b6..ba2669a5ea7 100644 --- a/spec/controllers/dashboard/milestones_controller_spec.rb +++ b/spec/controllers/dashboard/milestones_controller_spec.rb @@ -17,7 +17,7 @@ describe Dashboard::MilestonesController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'milestone tabs' diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb index 3458d679107..187542ba30c 100644 --- a/spec/controllers/dashboard_controller_spec.rb +++ b/spec/controllers/dashboard_controller_spec.rb @@ -5,7 +5,7 @@ describe DashboardController do let(:project) { create(:project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/groups/boards_controller_spec.rb b/spec/controllers/groups/boards_controller_spec.rb index 0f5bde62006..bf41aa0706f 100644 --- a/spec/controllers/groups/boards_controller_spec.rb +++ b/spec/controllers/groups/boards_controller_spec.rb @@ -5,7 +5,7 @@ describe Groups::BoardsController do let(:user) { create(:user) } before do - group.add_master(user) + group.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index 733386500ca..f7068546093 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -28,7 +28,7 @@ describe Groups::MilestonesController do before do sign_in(user) group.add_owner(user) - project.add_master(user) + project.add_maintainer(user) end describe '#index' do diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb index 5770d15557c..598fb84552f 100644 --- a/spec/controllers/groups/runners_controller_spec.rb +++ b/spec/controllers/groups/runners_controller_spec.rb @@ -14,7 +14,7 @@ describe Groups::RunnersController do before do sign_in(user) - group.add_master(user) + group.add_maintainer(user) end describe '#update' do diff --git a/spec/controllers/groups/settings/ci_cd_controller_spec.rb b/spec/controllers/groups/settings/ci_cd_controller_spec.rb index e9f0924caba..ea18122e0c3 100644 --- a/spec/controllers/groups/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/groups/settings/ci_cd_controller_spec.rb @@ -5,7 +5,7 @@ describe Groups::Settings::CiCdController do let(:user) { create(:user) } before do - group.add_master(user) + group.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/groups/variables_controller_spec.rb b/spec/controllers/groups/variables_controller_spec.rb index 39a36b92bb4..e5ac5634f95 100644 --- a/spec/controllers/groups/variables_controller_spec.rb +++ b/spec/controllers/groups/variables_controller_spec.rb @@ -6,7 +6,7 @@ describe Groups::VariablesController do before do sign_in(user) - group.add_master(user) + group.add_maintainer(user) end describe 'GET #show' do diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 8688fb33f0d..7a037828035 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -7,7 +7,7 @@ describe GroupsController do let(:project) { create(:project, namespace: group) } let!(:group_member) { create(:group_member, group: group, user: user) } let!(:owner) { group.add_owner(create(:user)).user } - let!(:master) { group.add_master(create(:user)).user } + let!(:maintainer) { group.add_maintainer(create(:user)).user } let!(:developer) { group.add_developer(create(:user)).user } let!(:guest) { group.add_guest(create(:user)).user } @@ -62,7 +62,7 @@ describe GroupsController do [true, false].each do |can_create_group_status| context "and can_create_group is #{can_create_group_status}" do before do - User.where(id: [admin, owner, master, developer, guest]).update_all(can_create_group: can_create_group_status) + User.where(id: [admin, owner, maintainer, developer, guest]).update_all(can_create_group: can_create_group_status) end [:admin, :owner].each do |member_type| @@ -73,7 +73,7 @@ describe GroupsController do end end - [:guest, :developer, :master].each do |member_type| + [:guest, :developer, :maintainer].each do |member_type| context "and logged in as #{member_type.capitalize}" do it_behaves_like 'member without ability to create subgroups' do let(:member) { send(member_type) } diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb index acfa2730d94..17c9a61f339 100644 --- a/spec/controllers/projects/avatars_controller_spec.rb +++ b/spec/controllers/projects/avatars_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::AvatarsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb index e7cddf8cfbf..dfe34171b55 100644 --- a/spec/controllers/projects/badges_controller_spec.rb +++ b/spec/controllers/projects/badges_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::BadgesController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb index 88d4f4e9cd0..fe4c4863717 100644 --- a/spec/controllers/projects/blame_controller_spec.rb +++ b/spec/controllers/projects/blame_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::BlameController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 4dcb7dc6c87..32cd7c6e70a 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -108,7 +108,7 @@ describe Projects::BlobController do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -230,12 +230,12 @@ describe Projects::BlobController do end end - context 'as master' do - let(:master) { create(:user) } + context 'as maintainer' do + let(:maintainer) { create(:user) } before do - project.add_master(master) - sign_in(master) + project.add_maintainer(maintainer) + sign_in(maintainer) get :edit, default_params end @@ -263,7 +263,7 @@ describe Projects::BlobController do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb index 509f19ed030..096efc1c7b2 100644 --- a/spec/controllers/projects/boards_controller_spec.rb +++ b/spec/controllers/projects/boards_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::BoardsController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 4860ea5dcce..31471cde420 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::BranchesController do let(:developer) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user) allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz']) diff --git a/spec/controllers/projects/clusters/applications_controller_spec.rb b/spec/controllers/projects/clusters/applications_controller_spec.rb index 99fdff5f846..9e17e392d3d 100644 --- a/spec/controllers/projects/clusters/applications_controller_spec.rb +++ b/spec/controllers/projects/clusters/applications_controller_spec.rb @@ -17,7 +17,7 @@ describe Projects::Clusters::ApplicationsController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -70,7 +70,7 @@ describe Projects::Clusters::ApplicationsController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index e47ccdc9aea..42917d0d505 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -11,7 +11,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -61,7 +61,7 @@ describe Projects::ClustersController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -79,7 +79,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -142,7 +142,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -156,7 +156,7 @@ describe Projects::ClustersController do describe 'security' do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -185,7 +185,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -236,7 +236,7 @@ describe Projects::ClustersController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -267,7 +267,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -286,7 +286,7 @@ describe Projects::ClustersController do describe 'security' do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -306,7 +306,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -327,7 +327,7 @@ describe Projects::ClustersController do describe 'security' do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -350,7 +350,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -365,7 +365,7 @@ describe Projects::ClustersController do describe 'security' do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -386,7 +386,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -437,7 +437,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -525,7 +525,7 @@ describe Projects::ClustersController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -552,7 +552,7 @@ describe Projects::ClustersController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -605,7 +605,7 @@ describe Projects::ClustersController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index 003fec8ac68..916a4be2567 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -9,7 +9,7 @@ describe Projects::CommitController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET show' do diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index 55ed276f96b..d44048fdf55 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::CommitsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe "GET show" do diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index b15cde4314e..8695aa826bb 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::CompareController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET index' do diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index 5516c95d044..5c79269e8f1 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::CycleAnalyticsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'cycle analytics not set up flag' do diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index 97db69427e9..d2f133f972a 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::DeployKeysController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb index 6c67dfde63a..d1c960e895d 100644 --- a/spec/controllers/projects/deployments_controller_spec.rb +++ b/spec/controllers/projects/deployments_controller_spec.rb @@ -8,7 +8,7 @@ describe Projects::DeploymentsController do let(:environment) { create(:environment, name: 'production', project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 63cef579864..b86029a4baf 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -9,7 +9,7 @@ describe Projects::EnvironmentsController do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb index 505fe82851a..66fe41108e2 100644 --- a/spec/controllers/projects/find_file_controller_spec.rb +++ b/spec/controllers/projects/find_file_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::FindFileController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index c3605555fe7..da78592a6f6 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::GraphsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET languages' do diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index 78c6f7839b4..879aff26deb 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::GroupLinksController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index 2d473d5bf52..0f3033b0933 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::HooksController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index 6f06210f3de..adf3c78ae51 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::ImportsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET #show' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 3a41f0fc07a..ff1835a34c2 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -695,7 +695,7 @@ describe Projects::IssuesController do let(:project) { merge_request.source_project } before do - project.add_master(user) + project.add_maintainer(user) sign_in user end @@ -869,7 +869,7 @@ describe Projects::IssuesController do def post_spam admin = create(:admin) create(:user_agent_detail, subject: issue) - project.add_master(admin) + project.add_maintainer(admin) sign_in(admin) post :mark_as_spam, { namespace_id: project.namespace, diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index e6332a10265..1aca44c6e74 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -216,17 +216,19 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'when trace artifact is in ObjectStorage' do + let(:url) { 'http://object-storage/trace' } + let(:file_path) { expand_fixture_path('trace/sample_trace') } let!(:job) { create(:ci_build, :success, :trace_artifact, pipeline: pipeline) } before do allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false } - allow_any_instance_of(JobArtifactUploader).to receive(:url) { remote_trace_url } - allow_any_instance_of(JobArtifactUploader).to receive(:size) { remote_trace_size } + allow_any_instance_of(JobArtifactUploader).to receive(:url) { url } + allow_any_instance_of(JobArtifactUploader).to receive(:size) { File.size(file_path) } end context 'when there are no network issues' do before do - stub_remote_trace_206 + stub_remote_url_206(url, file_path) get_trace end @@ -241,11 +243,11 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'when there is a network issue' do before do - stub_remote_trace_500 + stub_remote_url_500(url) end it 'returns a trace' do - expect { get_trace }.to raise_error(Gitlab::Ci::Trace::HttpIO::FailedToGetChunkError) + expect { get_trace }.to raise_error(Gitlab::HttpIO::FailedToGetChunkError) end end end @@ -429,7 +431,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do end describe 'POST erase' do - let(:role) { :master } + let(:role) { :maintainer } before do project.add_role(user, role) diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index 452d7e23983..273702e6d21 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::LabelsController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index c5ac0be27bb..c2a334a849c 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::MattermostsController do let!(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index 00d76f3c39a..d8995f98575 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -16,7 +16,7 @@ describe Projects::MergeRequests::CreationsController do end before do - fork_project.add_master(user) + fork_project.add_maintainer(user) Projects::ForkService.new(project, user).execute(fork_project) sign_in(user) end @@ -94,7 +94,7 @@ describe Projects::MergeRequests::CreationsController do let(:other_project) { create(:project, :repository) } before do - other_project.add_master(user) + other_project.add_maintainer(user) end context 'when the path exists in the diff' do diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index ec82b35f227..9dc06436c72 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -140,7 +140,7 @@ describe Projects::MergeRequests::DiffsController do let(:other_project) { create(:project) } before do - other_project.add_master(user) + other_project.add_maintainer(user) diff_for_path(old_path: existing_path, new_path: existing_path, project_id: other_project) end diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index b1d83246238..ea906cf7f32 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -11,7 +11,7 @@ describe Projects::MilestonesController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/pages_controller_spec.rb b/spec/controllers/projects/pages_controller_spec.rb index 8d2fa6a1740..927b6e0c473 100644 --- a/spec/controllers/projects/pages_controller_spec.rb +++ b/spec/controllers/projects/pages_controller_spec.rb @@ -14,7 +14,7 @@ describe Projects::PagesController do before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET show' do diff --git a/spec/controllers/projects/pages_domains_controller_spec.rb b/spec/controllers/projects/pages_domains_controller_spec.rb index d4058a5c515..75871eab1ab 100644 --- a/spec/controllers/projects/pages_domains_controller_spec.rb +++ b/spec/controllers/projects/pages_domains_controller_spec.rb @@ -19,7 +19,7 @@ describe Projects::PagesDomainsController do before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET show' do diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb index 4cdaa54e0bc..7179423dde2 100644 --- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb +++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb @@ -121,7 +121,7 @@ describe Projects::PipelineSchedulesController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_allowed_for(:developer).of(project) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -274,7 +274,7 @@ describe Projects::PipelineSchedulesController do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -292,19 +292,19 @@ describe Projects::PipelineSchedulesController do it { expect { go }.to be_allowed_for(developer_1) } it { expect { go }.to be_denied_for(:developer).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } end - context 'when a master created a pipeline schedule' do - let(:master_1) { create(:user) } - let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: master_1) } + context 'when a maintainer created a pipeline schedule' do + let(:maintainer_1) { create(:user) } + let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: maintainer_1) } before do - project.add_master(master_1) + project.add_maintainer(maintainer_1) end - it { expect { go }.to be_allowed_for(master_1) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(maintainer_1) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_denied_for(:developer).of(project) } end end @@ -331,7 +331,7 @@ describe Projects::PipelineSchedulesController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -346,7 +346,7 @@ describe Projects::PipelineSchedulesController do describe 'security' do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -364,7 +364,7 @@ describe Projects::PipelineSchedulesController do describe 'security' do it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } it { expect { go }.to be_allowed_for(:developer).of(project).own(pipeline_schedule) } it { expect { go }.to be_denied_for(:reporter).of(project) } it { expect { go }.to be_denied_for(:guest).of(project) } @@ -453,9 +453,9 @@ describe Projects::PipelineSchedulesController do end end - context 'when a master makes the request' do + context 'when a maintainer makes the request' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/pipelines_settings_controller_spec.rb b/spec/controllers/projects/pipelines_settings_controller_spec.rb index 694896b6bcf..b1ba9f74e38 100644 --- a/spec/controllers/projects/pipelines_settings_controller_spec.rb +++ b/spec/controllers/projects/pipelines_settings_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::PipelinesSettingsController do let(:project) { project_auto_devops.project } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index d84b31ad978..519af10d78c 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -37,7 +37,7 @@ describe Projects::ProjectMembersController do context 'when user has enough rights' do before do - project.add_master(user) + project.add_maintainer(user) end it 'adds user to members' do @@ -70,7 +70,7 @@ describe Projects::ProjectMembersController do let(:requester) { create(:project_member, :access_request, project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -121,7 +121,7 @@ describe Projects::ProjectMembersController do context 'when user has enough rights' do before do - project.add_master(user) + project.add_maintainer(user) end it '[HTML] removes user from members' do @@ -181,7 +181,7 @@ describe Projects::ProjectMembersController do let(:project) { create(:project, namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) end it 'cannot remove themselves from the project' do @@ -263,7 +263,7 @@ describe Projects::ProjectMembersController do context 'when user has enough rights' do before do - project.add_master(user) + project.add_maintainer(user) end it 'adds user to members' do @@ -285,7 +285,7 @@ describe Projects::ProjectMembersController do let(:member) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) another_project.add_guest(member) sign_in(user) end @@ -332,7 +332,7 @@ describe Projects::ProjectMembersController do context 'when creating owner' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -346,9 +346,9 @@ describe Projects::ProjectMembersController do end end - context 'when create master' do + context 'when create maintainer' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -356,7 +356,7 @@ describe Projects::ProjectMembersController do expect do post :create, user_ids: stranger.id, namespace_id: project.namespace, - access_level: Member::MASTER, + access_level: Member::MAINTAINER, project_id: project end.to change { project.members.count }.by(1) end diff --git a/spec/controllers/projects/prometheus/metrics_controller_spec.rb b/spec/controllers/projects/prometheus/metrics_controller_spec.rb index 871dcf5c796..5c56a712245 100644 --- a/spec/controllers/projects/prometheus/metrics_controller_spec.rb +++ b/spec/controllers/projects/prometheus/metrics_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::Prometheus::MetricsController do let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/protected_branches_controller_spec.rb b/spec/controllers/projects/protected_branches_controller_spec.rb index 096e29bc39f..ac812707e74 100644 --- a/spec/controllers/projects/protected_branches_controller_spec.rb +++ b/spec/controllers/projects/protected_branches_controller_spec.rb @@ -8,7 +8,7 @@ describe Projects::ProtectedBranchesController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) end describe "GET #index" do @@ -20,10 +20,10 @@ describe Projects::ProtectedBranchesController do end describe "POST #create" do - let(:master_access_level) { [{ access_level: Gitlab::Access::MASTER }] } + let(:maintainer_access_level) { [{ access_level: Gitlab::Access::MAINTAINER }] } let(:access_level_params) do - { merge_access_levels_attributes: master_access_level, - push_access_levels_attributes: master_access_level } + { merge_access_levels_attributes: maintainer_access_level, + push_access_levels_attributes: maintainer_access_level } end let(:create_params) { attributes_for(:protected_branch).merge(access_level_params) } diff --git a/spec/controllers/projects/protected_tags_controller_spec.rb b/spec/controllers/projects/protected_tags_controller_spec.rb index b6de90039f3..20440c5a5d5 100644 --- a/spec/controllers/projects/protected_tags_controller_spec.rb +++ b/spec/controllers/projects/protected_tags_controller_spec.rb @@ -15,7 +15,7 @@ describe Projects::ProtectedTagsController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 2082dd2cff0..b1e0b496ede 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -15,7 +15,7 @@ describe Projects::RunnersController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe '#update' do diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 61f35cf325b..45cea8c1351 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -9,7 +9,7 @@ describe Projects::ServicesController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe '#test' do diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index d53fe9bf734..1f14a0cc381 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::Settings::CiCdController do let(:project) { project_auto_devops.project } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -27,7 +27,7 @@ describe Projects::Settings::CiCdController do let!(:shared_runner) { create(:ci_runner, :instance) } it 'sets assignable project runners only' do - group.add_master(user) + group.add_maintainer(user) get :show, namespace_id: project.namespace, project_id: project @@ -40,7 +40,7 @@ describe Projects::Settings::CiCdController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) end diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb index 77df9a6f567..a2484c04c7a 100644 --- a/spec/controllers/projects/settings/integrations_controller_spec.rb +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::Settings::IntegrationsController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb index 3a4014b7768..9cee40b7553 100644 --- a/spec/controllers/projects/settings/repository_controller_spec.rb +++ b/spec/controllers/projects/settings/repository_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::Settings::RepositoryController do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index e7c0b484ede..9c383bd7628 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -6,8 +6,8 @@ describe Projects::SnippetsController do let(:user2) { create(:user) } before do - project.add_master(user) - project.add_master(user2) + project.add_maintainer(user) + project.add_maintainer(user2) end describe 'GET #index' do @@ -291,7 +291,7 @@ describe Projects::SnippetsController do def mark_as_spam admin = create(:admin) create(:user_agent_detail, subject: snippet) - project.add_master(admin) + project.add_maintainer(admin) sign_in(admin) post :mark_as_spam, diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb index 8fcfa3c9ecd..d7f07aa2b01 100644 --- a/spec/controllers/projects/templates_controller_spec.rb +++ b/spec/controllers/projects/templates_controller_spec.rb @@ -13,7 +13,7 @@ describe Projects::TemplatesController do end before do - project.add_user(user, Gitlab::Access::MASTER) + project.add_user(user, Gitlab::Access::MAINTAINER) project.repository.create_file(user, file_path_1, 'something valid', message: 'test 3', branch_name: 'master') end diff --git a/spec/controllers/projects/todos_controller_spec.rb b/spec/controllers/projects/todos_controller_spec.rb index 58f2817c7cc..1ce7e84bef9 100644 --- a/spec/controllers/projects/todos_controller_spec.rb +++ b/spec/controllers/projects/todos_controller_spec.rb @@ -5,29 +5,10 @@ describe Projects::TodosController do let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project) } - let(:parent) { project } - - shared_examples 'project todos actions' do - it_behaves_like 'todos actions' - - context 'when not authorized for resource' do - before do - project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) - project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE) - project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE) - sign_in(user) - end - - it "doesn't create todo" do - expect { post_create }.not_to change { user.todos.count } - expect(response).to have_gitlab_http_status(404) - end - end - end context 'Issues' do describe 'POST create' do - def post_create + def go post :create, namespace_id: project.namespace, project_id: project, @@ -36,13 +17,66 @@ describe Projects::TodosController do format: 'html' end - it_behaves_like 'project todos actions' + context 'when authorized' do + before do + sign_in(user) + project.add_developer(user) + end + + it 'creates todo for issue' do + expect do + go + end.to change { user.todos.count }.by(1) + + expect(response).to have_gitlab_http_status(200) + end + + it 'returns todo path and pending count' do + go + + expect(response).to have_gitlab_http_status(200) + expect(json_response['count']).to eq 1 + expect(json_response['delete_path']).to match(%r{/dashboard/todos/\d{1}}) + end + end + + context 'when not authorized for project' do + it 'does not create todo for issue that user has no access to' do + sign_in(user) + expect do + go + end.to change { user.todos.count }.by(0) + + expect(response).to have_gitlab_http_status(404) + end + + it 'does not create todo for issue when user not logged in' do + expect do + go + end.to change { user.todos.count }.by(0) + + expect(response).to have_gitlab_http_status(302) + end + end + + context 'when not authorized for issue' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE) + sign_in(user) + end + + it "doesn't create todo" do + expect { go }.not_to change { user.todos.count } + expect(response).to have_gitlab_http_status(404) + end + end end end context 'Merge Requests' do describe 'POST create' do - def post_create + def go post :create, namespace_id: project.namespace, project_id: project, @@ -51,7 +85,60 @@ describe Projects::TodosController do format: 'html' end - it_behaves_like 'project todos actions' + context 'when authorized' do + before do + sign_in(user) + project.add_developer(user) + end + + it 'creates todo for merge request' do + expect do + go + end.to change { user.todos.count }.by(1) + + expect(response).to have_gitlab_http_status(200) + end + + it 'returns todo path and pending count' do + go + + expect(response).to have_gitlab_http_status(200) + expect(json_response['count']).to eq 1 + expect(json_response['delete_path']).to match(%r{/dashboard/todos/\d{1}}) + end + end + + context 'when not authorized for project' do + it 'does not create todo for merge request user has no access to' do + sign_in(user) + expect do + go + end.to change { user.todos.count }.by(0) + + expect(response).to have_gitlab_http_status(404) + end + + it 'does not create todo for merge request user has no access to' do + expect do + go + end.to change { user.todos.count }.by(0) + + expect(response).to have_gitlab_http_status(302) + end + end + + context 'when not authorized for merge_request' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE) + sign_in(user) + end + + it "doesn't create todo" do + expect { go }.not_to change { user.todos.count } + expect(response).to have_gitlab_http_status(404) + end + end end end end diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index d3188f054cf..9982b49eebb 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::TreeController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb index 68019743be0..9afd1f751c6 100644 --- a/spec/controllers/projects/variables_controller_spec.rb +++ b/spec/controllers/projects/variables_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::VariablesController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'GET #show' do diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index fd7d867f9e5..94644b1f9fd 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -759,7 +759,7 @@ describe ProjectsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end context 'when project export is enabled' do @@ -787,7 +787,7 @@ describe ProjectsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end context 'object storage disabled' do @@ -847,7 +847,7 @@ describe ProjectsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end context 'when project export is enabled' do @@ -875,7 +875,7 @@ describe ProjectsController do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end context 'when project export is enabled' do diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index eb94d395a9e..bcf289f36a9 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -269,13 +269,13 @@ describe UploadsController do context "when the user has access to the project" do before do - project.add_master(user) + project.add_maintainer(user) end context "when the user is blocked" do before do user.block - project.add_master(user) + project.add_maintainer(user) end it "redirects to the sign in page" do @@ -475,13 +475,13 @@ describe UploadsController do context "when the user has access to the project" do before do - project.add_master(user) + project.add_maintainer(user) end context "when the user is blocked" do before do user.block - project.add_master(user) + project.add_maintainer(user) end it "redirects to the sign in page" do diff --git a/spec/factories/group_members.rb b/spec/factories/group_members.rb index 1c2214e9481..47036560b9d 100644 --- a/spec/factories/group_members.rb +++ b/spec/factories/group_members.rb @@ -7,7 +7,7 @@ FactoryBot.define do trait(:guest) { access_level GroupMember::GUEST } trait(:reporter) { access_level GroupMember::REPORTER } trait(:developer) { access_level GroupMember::DEVELOPER } - trait(:master) { access_level GroupMember::MASTER } + trait(:maintainer) { access_level GroupMember::MAINTAINER } trait(:owner) { access_level GroupMember::OWNER } trait(:access_request) { requested_at Time.now } diff --git a/spec/factories/project_members.rb b/spec/factories/project_members.rb index 4260f52498d..22a8085ea45 100644 --- a/spec/factories/project_members.rb +++ b/spec/factories/project_members.rb @@ -2,12 +2,12 @@ FactoryBot.define do factory :project_member do user project - master + maintainer trait(:guest) { access_level ProjectMember::GUEST } trait(:reporter) { access_level ProjectMember::REPORTER } trait(:developer) { access_level ProjectMember::DEVELOPER } - trait(:master) { access_level ProjectMember::MASTER } + trait(:maintainer) { access_level ProjectMember::MAINTAINER } trait(:access_request) { requested_at Time.now } trait(:invited) do diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index f77ded23b18..fec1bea2751 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -47,7 +47,7 @@ FactoryBot.define do # user have access to the project. Our specs don't use said service class, # thus we must manually refresh things here. unless project.group || project.pending_delete - project.add_master(project.owner) + project.add_maintainer(project.owner) end project.group&.refresh_members_authorized_projects diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb index 60956511834..5457c0d2a8f 100644 --- a/spec/factories/protected_branches.rb +++ b/spec/factories/protected_branches.rb @@ -39,23 +39,23 @@ FactoryBot.define do end end - trait :masters_can_push do + trait :maintainers_can_push do transient do default_push_level false end after(:build) do |protected_branch| - protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER) + protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end end after(:build) do |protected_branch, evaluator| if evaluator.default_access_level && evaluator.default_push_level - protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER) + protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end if evaluator.default_access_level && evaluator.default_merge_level - protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER) + protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end end diff --git a/spec/factories/protected_tags.rb b/spec/factories/protected_tags.rb index df9c8b3cb63..2b81d089549 100644 --- a/spec/factories/protected_tags.rb +++ b/spec/factories/protected_tags.rb @@ -27,19 +27,19 @@ FactoryBot.define do end end - trait :masters_can_create do + trait :maintainers_can_create do transient do default_access_level false end after(:build) do |protected_tag| - protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER) + protected_tag.create_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end end after(:build) do |protected_tag, evaluator| if evaluator.default_access_level - protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER) + protected_tag.create_access_levels.new(access_level: Gitlab::Access::MAINTAINER) end end end diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index 14486c80341..94f8caedfa6 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -1,8 +1,8 @@ FactoryBot.define do factory :todo do project - author { project&.creator || user } - user { project&.creator || user } + author { project.creator } + user { project.creator } target factory: :issue action { Todo::ASSIGNED } diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index 5b0a53688c2..96dfde2e08c 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -168,7 +168,7 @@ describe 'Admin Groups' do it 'renders shared project' do empty_project = create(:project) empty_project.project_group_links.create!( - group_access: Gitlab::Access::MASTER, + group_access: Gitlab::Access::MAINTAINER, group: group ) diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 328e8f25f89..d6ee256f5b5 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -88,7 +88,7 @@ describe "Admin::Projects" do describe 'add admin himself to a project' do before do - project.add_master(user) + project.add_maintainer(user) end it 'adds admin a to a project as developer', :js do @@ -110,7 +110,7 @@ describe "Admin::Projects" do describe 'admin remove himself from a project' do before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(current_user) end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 9c6758abe86..a852ca689e7 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -272,6 +272,16 @@ describe 'Admin updates settings' do expect(Gitlab::CurrentSettings.allow_local_requests_from_hooks_and_services).to be true end + it 'Enable hiding third party offers' do + page.within('.as-third-party-offers') do + check 'Do not display offers from third parties within GitLab' + click_button 'Save changes' + end + + expect(page).to have_content "Application settings saved successfully" + expect(Gitlab::CurrentSettings.hide_third_party_offers).to be true + end + it 'Change Slack Notifications Service template settings' do first(:link, 'Service Templates').click click_link 'Slack notifications' diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index da7749b42d2..bd4c00d97b1 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -8,8 +8,8 @@ describe "Dashboard Issues Feed" do let!(:project2) { create(:project) } before do - project1.add_master(user) - project2.add_master(user) + project1.add_maintainer(user) + project2.add_maintainer(user) end describe "atom feed" do diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb index 462eab07a75..86b3f88298f 100644 --- a/spec/features/atom/dashboard_spec.rb +++ b/spec/features/atom/dashboard_spec.rb @@ -26,7 +26,7 @@ describe "Dashboard Feed" do let(:note) { create(:note, noteable: issue, author: user, note: 'Bug confirmed', project: project) } before do - project.add_master(user) + project.add_maintainer(user) issue_event(issue, user) note_event(note, user) visit dashboard_projects_path(:atom, feed_token: user.feed_token) diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index eeaaa40fe21..8d7df346abb 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -47,7 +47,7 @@ describe "User Feed" do let!(:push_event_payload) { create(:push_event_payload, event: push_event) } before do - project.add_master(user) + project.add_maintainer(user) issue_event(issue, user) note_event(note, user) merge_request_event(merge_request, user) diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index 7a14a441088..eebc987499d 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -12,7 +12,7 @@ describe 'Issue Boards add issue modal', :js do let!(:issue2) { create(:issue, project: project, title: 'hij', description: 'klm') } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index f6e0dee28c6..a0af2dea3ad 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -11,8 +11,8 @@ describe 'Issue Boards', :js do let!(:user2) { create(:user) } before do - project.add_master(user) - project.add_master(user2) + project.add_maintainer(user) + project.add_maintainer(user2) set_cookie('sidebar_collapsed', 'true') diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 32bd7b88840..ec0ca21450a 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -13,7 +13,7 @@ describe 'Issue Boards', :js do let!(:issue3) { create(:labeled_issue, project: project, title: 'testing 3', labels: [label], relative_position: 1) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb index be9c6a51c29..615223a2a88 100644 --- a/spec/features/boards/modal_filter_spec.rb +++ b/spec/features/boards/modal_filter_spec.rb @@ -10,7 +10,7 @@ describe 'Issue Boards add issue modal filtering', :js do let!(:issue1) { create(:issue, project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index 7a95f5cf871..0bf1ecbc433 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -8,7 +8,7 @@ describe 'Issue Boards new issue', :js do context 'authorized user' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index a03aa681827..ee38e756f9e 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -22,7 +22,7 @@ describe 'Issue Boards', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb index 271c610dcc8..de2cb4c335e 100644 --- a/spec/features/boards/sub_group_project_spec.rb +++ b/spec/features/boards/sub_group_project_spec.rb @@ -11,7 +11,7 @@ describe 'Sub-group project issue boards', :js do let!(:issue) { create(:labeled_issue, project: project, labels: [label]) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 29fcf89fa7a..8989b2051bb 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -188,7 +188,7 @@ describe 'Commits' do let(:branch_name) { 'master' } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_commits_path(project, branch_name) end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index dfcd7ada23b..32c75cae0a1 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -12,7 +12,7 @@ describe 'Cycle Analytics', :js do context 'as an allowed user' do context 'when project is new' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) @@ -39,7 +39,7 @@ describe 'Cycle Analytics', :js do context "when there's cycle analytics data" do before do allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue]) - project.add_master(user) + project.add_maintainer(user) @build = create_cycle(user, project, issue, mr, milestone, pipeline) deploy_master(user, project) @@ -95,7 +95,7 @@ describe 'Cycle Analytics', :js do before do user.update_attribute(:preferred_language, 'es') - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_cycle_analytics_path(project) wait_for_requests diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb index 9ed912820f7..bf91dc121d8 100644 --- a/spec/features/dashboard/activity_spec.rb +++ b/spec/features/dashboard/activity_spec.rb @@ -60,7 +60,7 @@ describe 'Dashboard > Activity' do end before do - project.add_master(user) + project.add_maintainer(user) visit activity_dashboard_path wait_for_requests diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index b36231fd78b..6a0cd848345 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -6,8 +6,8 @@ RSpec.describe 'Dashboard Archived Project' do let(:archived_project) { create(:project, :archived) } before do - project.add_master(user) - archived_project.add_master(user) + project.add_maintainer(user) + archived_project.add_maintainer(user) sign_in(user) diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index 28bff4d2821..d7234158fa1 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -8,7 +8,7 @@ describe 'Tooltips on .timeago dates', :js do context 'on the activity tab' do before do - project.add_master(user) + project.add_maintainer(user) Event.create( project: project, author_id: user.id, action: Event::JOINED, updated_at: created_date, created_at: created_date) @@ -27,7 +27,7 @@ describe 'Tooltips on .timeago dates', :js do context 'on the snippets tab' do before do - project.add_master(user) + project.add_maintainer(user) create(:snippet, author: user, updated_at: created_date, created_at: created_date) sign_in user diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index 340262be502..95e2610dd4a 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -11,7 +11,7 @@ describe 'Dashboard Issues filtering', :js do let!(:issue2) { create(:issue, project: project, author: user, assignees: [user], milestone: milestone) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit_issues diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 3cc7b38550d..4ae062f242a 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -12,7 +12,7 @@ RSpec.describe 'Dashboard Issues' do let!(:other_issue) { create :issue, project: project } before do - [project, project_with_issues_disabled].each { |project| project.add_master(current_user) } + [project, project_with_issues_disabled].each { |project| project.add_maintainer(current_user) } sign_in(current_user) visit issues_dashboard_path(assignee_id: current_user.id) end diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index 46d7a82d468..f51142f5790 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -12,7 +12,7 @@ describe 'Dashboard Merge Requests' do let(:forked_project) { fork_project(public_project, current_user, repository: true) } before do - project.add_master(current_user) + project.add_maintainer(current_user) sign_in(current_user) end @@ -20,7 +20,7 @@ describe 'Dashboard Merge Requests' do let(:project_with_disabled_merge_requests) { create(:project, :merge_requests_disabled) } before do - project_with_disabled_merge_requests.add_master(current_user) + project_with_disabled_merge_requests.add_maintainer(current_user) visit merge_requests_dashboard_path end diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb index 6fcde35f541..21de7c2f06f 100644 --- a/spec/features/dashboard/milestone_tabs_spec.rb +++ b/spec/features/dashboard/milestone_tabs_spec.rb @@ -14,7 +14,7 @@ describe 'Dashboard milestone tabs', :js do let!(:merge_request) { create(:labeled_merge_request, source_project: project, target_project: project, milestone: project_milestone, labels: [label]) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit dashboard_milestone_path(milestone.safe_title, title: milestone.title) diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb index c0699a72521..0db69432702 100644 --- a/spec/features/dashboard/milestones_spec.rb +++ b/spec/features/dashboard/milestones_spec.rb @@ -16,7 +16,7 @@ describe 'Dashboard > Milestones' do let(:project) { create(:project, namespace: user.namespace) } let!(:milestone) { create(:milestone, project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit dashboard_milestones_path end diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index cfd6329fad0..498775acff3 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -5,7 +5,7 @@ describe 'Project member activity', :js do let(:project) { create(:project, :public, name: 'x', namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) end def visit_activities_and_wait_with_event(event_type) diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index 92f4d4b854c..3746d37b9cd 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -7,7 +7,7 @@ describe 'Dashboard > User filters projects' do let(:project2) { create(:project, name: 'Treasure', namespace: user2.namespace) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb index 69d35cdbc72..7a3b1d7ed47 100644 --- a/spec/features/discussion_comments/commit_spec.rb +++ b/spec/features/discussion_comments/commit_spec.rb @@ -8,7 +8,7 @@ describe 'Discussion Comments Commit', :js do let(:merge_request) { create(:merge_request, source_project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_commit_path(project, sample_commit.id) diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb index 9812eaf3420..5ec19460bbd 100644 --- a/spec/features/discussion_comments/issue_spec.rb +++ b/spec/features/discussion_comments/issue_spec.rb @@ -6,7 +6,7 @@ describe 'Discussion Comments Issue', :js do let(:issue) { create(:issue, project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_issue_path(project, issue) diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb index b0019c32189..f940e973923 100644 --- a/spec/features/discussion_comments/merge_request_spec.rb +++ b/spec/features/discussion_comments/merge_request_spec.rb @@ -6,7 +6,7 @@ describe 'Discussion Comments Merge Request', :js do let(:merge_request) { create(:merge_request, source_project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_merge_request_path(project, merge_request) diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb index 4a236c4639b..d330e89505e 100644 --- a/spec/features/discussion_comments/snippets_spec.rb +++ b/spec/features/discussion_comments/snippets_spec.rb @@ -6,7 +6,7 @@ describe 'Discussion Comments Snippet', :js do let(:snippet) { create(:project_snippet, :private, project: project, author: user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_snippet_path(project, snippet) diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index df64219de99..d7692181453 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -5,7 +5,7 @@ describe 'Global search' do let(:project) { create(:project, namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb index 5643240377b..89e0cdd8ed7 100644 --- a/spec/features/group_variables_spec.rb +++ b/spec/features/group_variables_spec.rb @@ -7,7 +7,7 @@ describe 'Group variables', :js do let(:page_path) { group_settings_ci_cd_path(group) } before do - group.add_master(user) + group.add_maintainer(user) gitlab_sign_in(user) visit page_path diff --git a/spec/features/groups/activity_spec.rb b/spec/features/groups/activity_spec.rb index 27520cf0e22..88fc12ae1e4 100644 --- a/spec/features/groups/activity_spec.rb +++ b/spec/features/groups/activity_spec.rb @@ -23,7 +23,7 @@ describe 'Group activity page' do let(:project) { create(:project, :public, namespace: group) } before do - project.add_master(user) + project.add_maintainer(user) visit path end diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index dd901b034f7..8f5ca781b2c 100644 --- a/spec/features/groups/empty_states_spec.rb +++ b/spec/features/groups/empty_states_spec.rb @@ -19,7 +19,7 @@ describe 'Group empty states' do let(:project) { create(:project, namespace: group) } before do - project.add_master(user) + project.add_maintainer(user) end context "the project has #{issuable_name}s" do diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index 2bab6aa3d48..97d8776b15a 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -80,10 +80,10 @@ describe 'Group issues page' do context 'projects with issues disabled' do describe 'issue dropdown' do - let(:user_in_group) { create(:group_member, :master, user: create(:user), group: group ).user } + let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } before do - [project, project_with_issues_disabled].each { |project| project.add_master(user_in_group) } + [project, project_with_issues_disabled].each { |project| project.add_maintainer(user_in_group) } sign_in(user_in_group) visit issues_group_path(group) end diff --git a/spec/features/groups/members/filter_members_spec.rb b/spec/features/groups/members/filter_members_spec.rb index 8b4f6dbcc50..386d81546d7 100644 --- a/spec/features/groups/members/filter_members_spec.rb +++ b/spec/features/groups/members/filter_members_spec.rb @@ -7,7 +7,7 @@ describe 'Groups > Members > Filter members' do before do group.add_owner(user) - group.add_master(user_with_2fa) + group.add_maintainer(user_with_2fa) sign_in(user) end diff --git a/spec/features/groups/members/master_manages_access_requests_spec.rb b/spec/features/groups/members/master_manages_access_requests_spec.rb index 4fdf1497781..bd615c99412 100644 --- a/spec/features/groups/members/master_manages_access_requests_spec.rb +++ b/spec/features/groups/members/master_manages_access_requests_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe 'Groups > Members > Master manages access requests' do - it_behaves_like 'Master manages access requests' do +describe 'Groups > Members > Maintainer manages access requests' do + it_behaves_like 'Maintainer manages access requests' do let(:entity) { create(:group, :public, :access_requestable) } let(:members_page_path) { group_group_members_path(entity) } end diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 5ab03cb6ee6..80df0618a6a 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Group milestones' do let(:group) { create(:group) } let!(:project) { create(:project_empty_repo, group: group) } - let(:user) { create(:group_member, :master, user: create(:user), group: group ).user } + let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user } around do |example| Timecop.freeze { example.run } diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb index 5deb55bc8bb..bc226ff41c1 100644 --- a/spec/features/groups/milestones_sorting_spec.rb +++ b/spec/features/groups/milestones_sorting_spec.rb @@ -9,7 +9,7 @@ describe 'Milestones sorting', :js do let!(:project_milestone2) { create(:milestone, project: project, title: 'v2.0', due_date: 5.days.from_now) } let!(:other_project_milestone2) { create(:milestone, project: other_project, title: 'v2.0', due_date: 5.days.from_now) } let!(:group_milestone) { create(:milestone, group: group, title: 'v3.0', due_date: 7.days.from_now) } - let(:user) { create(:group_member, :master, user: create(:user), group: group ).user } + let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user } before do sign_in(user) diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 053e3b189c3..e62bd6f8187 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -154,6 +154,12 @@ describe 'Group' do end end + it 'focuses confirmation field on remove group' do + click_button('Remove group') + + expect(page).to have_selector '#confirm_name_input:focus' + end + it 'removes group' do expect { remove_with_confirm('Remove group', group.path) }.to change {Group.count}.by(-1) expect(group.members.all.count).to be_zero diff --git a/spec/features/ics/dashboard_issues_spec.rb b/spec/features/ics/dashboard_issues_spec.rb index a4d05c25a90..ea714934ae7 100644 --- a/spec/features/ics/dashboard_issues_spec.rb +++ b/spec/features/ics/dashboard_issues_spec.rb @@ -8,7 +8,7 @@ describe 'Dashboard Issues Calendar Feed' do let(:milestone) { create(:milestone, project_id: project.id, title: 'v1.0') } before do - project.add_master(user) + project.add_maintainer(user) end context 'when authenticated' do diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb index b3f24c2966d..65989c36c1e 100644 --- a/spec/features/ide_spec.rb +++ b/spec/features/ide_spec.rb @@ -8,7 +8,7 @@ describe 'IDE', :js do let(:subgroup_project) { create(:project, :repository, namespace: subgroup) } before do - subgroup_project.add_master(user) + subgroup_project.add_maintainer(user) sign_in(user) visit project_path(subgroup_project) diff --git a/spec/features/import/manifest_import_spec.rb b/spec/features/import/manifest_import_spec.rb new file mode 100644 index 00000000000..e381d073804 --- /dev/null +++ b/spec/features/import/manifest_import_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe 'Import multiple repositories by uploading a manifest file', :js, :postgresql do + include Select2Helper + + let(:user) { create(:admin) } + let(:group) { create(:group) } + + before do + sign_in(user) + + group.add_owner(user) + end + + it 'parses manifest file and list repositories' do + visit new_import_manifest_path + + attach_file('manifest', Rails.root.join('spec/fixtures/aosp_manifest.xml')) + click_on 'List available repositories' + + expect(page).to have_button('Import all repositories') + expect(page).to have_content('https://android-review.googlesource.com/platform/build/blueprint') + end + + it 'imports succesfully imports a project' do + visit new_import_manifest_path + + attach_file('manifest', Rails.root.join('spec/fixtures/aosp_manifest.xml')) + click_on 'List available repositories' + + page.within(first_row) do + click_on 'Import' + + expect(page).to have_content 'Done' + expect(page).to have_content("#{group.full_path}/build/make") + end + end + + it 'renders an error if invalid file was provided' do + visit new_import_manifest_path + + attach_file('manifest', Rails.root.join('spec/fixtures/banana_sample.gif')) + click_on 'List available repositories' + + expect(page).to have_content 'The uploaded file is not a valid XML file.' + end + + def first_row + page.all('table.import-jobs tbody tr')[0] + end +end diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb index a986ddc4abc..9e1a12a9c2a 100644 --- a/spec/features/invites_spec.rb +++ b/spec/features/invites_spec.rb @@ -8,7 +8,7 @@ describe 'Invites' do let(:group_invite) { group.group_members.invite.last } before do - project.add_master(owner) + project.add_maintainer(owner) group.add_user(owner, Gitlab::Access::OWNER) group.add_developer('user@example.com', owner) group_invite.generate_invite_token! diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb index 3df77a104e8..de6f5fe1560 100644 --- a/spec/features/issuables/close_reopen_report_toggle_spec.rb +++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb @@ -46,7 +46,7 @@ describe 'Issuables Close/Reopen/Report toggle' do let(:issuable) { create(:issue, project: project) } before do - project.add_master(user) + project.add_maintainer(user) login_as user end @@ -83,7 +83,7 @@ describe 'Issuables Close/Reopen/Report toggle' do let(:issuable) { create(:merge_request, source_project: project) } before do - project.add_master(user) + project.add_maintainer(user) login_as user end diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index 1131e1711bf..bf60b18873c 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -11,7 +11,7 @@ describe 'Awards Emoji' do context 'authorized user' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 44ddc032656..06cb2e36334 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -11,7 +11,7 @@ describe 'Issues > Labels bulk assignment' do context 'as an allowed user', :js do before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index 32c6ac52f92..ada57285abf 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -14,7 +14,7 @@ describe 'Resolving all open discussions in a merge request from an issue', :js describe 'as a user with access to the project' do before do - project.add_master(user) + project.add_maintainer(user) sign_in user visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb index b8222283a98..b20730bdb22 100644 --- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb @@ -14,7 +14,7 @@ describe 'Resolve an open discussion in a merge request by creating an issue', : describe 'As a user with access to the project' do before do - project.add_master(user) + project.add_maintainer(user) sign_in user visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index c8115db9212..d011d2545bb 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -20,9 +20,9 @@ describe 'Dropdown assignee', :js do end before do - project.add_master(user) - project.add_master(user_john) - project.add_master(user_jacob) + project.add_maintainer(user) + project.add_maintainer(user_john) + project.add_maintainer(user_jacob) sign_in(user) create(:issue, project: project) @@ -224,7 +224,7 @@ describe 'Dropdown assignee', :js do expect(initial_size).to be > 0 new_user = create(:user) - project.add_master(new_user) + project.add_maintainer(new_user) find('.filtered-search-box .clear-search').click input_filtered_search('assignee:', submit: false, extra_space: false) diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index 70b4f11410d..50d819a6161 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -28,9 +28,9 @@ describe 'Dropdown author', :js do end before do - project.add_master(user) - project.add_master(user_john) - project.add_master(user_jacob) + project.add_maintainer(user) + project.add_maintainer(user_john) + project.add_maintainer(user_jacob) sign_in(user) create(:issue, project: project) @@ -195,7 +195,7 @@ describe 'Dropdown author', :js do expect(initial_size).to be > 0 new_user = create(:user) - project.add_master(new_user) + project.add_maintainer(new_user) find('.filtered-search-box .clear-search').click filtered_search.set('author') send_keys_to_filtered_search(':') diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb index 436625a6f7b..be229e8aa7d 100644 --- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb @@ -28,7 +28,7 @@ describe 'Dropdown emoji', :js do end before do - project.add_master(user) + project.add_maintainer(user) create_list(:award_emoji, 2, user: user, name: 'thumbsup') create_list(:award_emoji, 1, user: user, name: 'thumbsdown') create_list(:award_emoji, 3, user: user, name: 'star') diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index ef40dddfd3a..b99c5a7f4e3 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -13,7 +13,7 @@ describe 'Dropdown hint', :js do end before do - project.add_master(user) + project.add_maintainer(user) create(:issue, project: project) end diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb index 18cdb199c70..ca5d506ab04 100644 --- a/spec/features/issues/filtered_search/dropdown_label_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb @@ -33,7 +33,7 @@ describe 'Dropdown label', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) create(:issue, project: project) diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index 94710c2f71f..f76d30056da 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -29,7 +29,7 @@ describe 'Dropdown milestone', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) create(:issue, project: project) diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 8dca81a8627..d4949de3f27 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -24,7 +24,7 @@ describe 'Filter issues', :js do end before do - project.add_master(user) + project.add_maintainer(user) create(:issue, project: project, author: user2, title: "Bug report 1") create(:issue, project: project, author: user2, title: "Bug report 2") diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index 268590da599..8abab3f35d6 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -8,7 +8,7 @@ describe 'Search bar', :js do let(:filtered_search) { find('.filtered-search') } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) create(:issue, project: project) diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index 0ae70c855db..6ac7ccd00f7 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -22,8 +22,8 @@ describe 'Visual tokens', :js do end before do - project.add_user(user, :master) - project.add_user(user_rock, :master) + project.add_user(user, :maintainer) + project.add_user(user_rock, :maintainer) sign_in(user) create(:issue, project: project) diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 2cb3ae08b0e..1456a2f0375 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -13,8 +13,8 @@ describe 'New/edit issue', :js do let!(:issue) { create(:issue, project: project, assignees: [user], milestone: milestone) } before do - project.add_master(user) - project.add_master(user2) + project.add_maintainer(user) + project.add_maintainer(user2) sign_in(user) end @@ -321,7 +321,7 @@ describe 'New/edit issue', :js do let(:sub_group_project) { create(:project, group: nested_group_1) } before do - sub_group_project.add_master(user) + sub_group_project.add_maintainer(user) visit new_project_issue_path(sub_group_project) end diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index a330ba4c8b3..98e37d8011a 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -7,7 +7,7 @@ describe 'GFM autocomplete', :js do let(:issue) { create(:issue, project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_issue_path(project, issue) diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index 73022afbda2..7cce45ff206 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -17,7 +17,7 @@ describe 'New issue', :js do recaptcha_private_key: 'test private key' ) - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb index d23f9059d0f..0114178b9be 100644 --- a/spec/features/issues/todo_spec.rb +++ b/spec/features/issues/todo_spec.rb @@ -6,7 +6,7 @@ describe 'Manually create a todo item from issue', :js do let!(:user) { create(:user)} before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_issue_path(project, issue) end diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index cd6a5977eb8..845a7c5fc42 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -6,7 +6,7 @@ describe 'Multiple issue updating from issues#index', :js do let!(:user) { create(:user)} before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index a28378b22ca..5926e442f24 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -12,7 +12,7 @@ describe 'Issues > User uses quick actions', :js do let(:project) { create(:project, :public) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_issue_path(project, issue) end @@ -196,7 +196,7 @@ describe 'Issues > User uses quick actions', :js do let(:target_project) { create(:project, :public) } before do - target_project.add_master(user) + target_project.add_maintainer(user) gitlab_sign_out sign_in(user) visit project_issue_path(project, issue) @@ -258,7 +258,7 @@ describe 'Issues > User uses quick actions', :js do let(:wontfix_target) { create(:label, project: target_project, title: 'wontfix') } before do - target_project.add_master(user) + target_project.add_maintainer(user) gitlab_sign_out sign_in(user) visit project_issue_path(project, issue) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index c6dcd97631d..4d9b8a10e04 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -398,7 +398,7 @@ describe 'Issues' do before do stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab") - project1.add_master(user) + project1.add_maintainer(user) visit namespace_project_issues_path(user.namespace, project1) end diff --git a/spec/features/markdown/gitlab_flavored_markdown_spec.rb b/spec/features/markdown/gitlab_flavored_markdown_spec.rb index 3c2186b3598..6997ca48427 100644 --- a/spec/features/markdown/gitlab_flavored_markdown_spec.rb +++ b/spec/features/markdown/gitlab_flavored_markdown_spec.rb @@ -6,7 +6,7 @@ describe "GitLab Flavored Markdown" do let(:issue) { create(:issue, project: project) } let(:fred) do create(:user, name: 'fred') do |user| - project.add_master(user) + project.add_maintainer(user) end end diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb index 1808d0c0a0c..7839b97122c 100644 --- a/spec/features/merge_request/maintainer_edits_fork_spec.rb +++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb @@ -18,7 +18,7 @@ describe 'a maintainer edits files on a source-branch of an MR from a fork', :js end before do - target_project.add_master(user) + target_project.add_maintainer(user) sign_in(user) visit project_merge_request_path(target_project, merge_request) diff --git a/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb index 0af37d76539..0ccab5b2fac 100644 --- a/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb +++ b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb @@ -71,7 +71,7 @@ describe 'create a merge request, allowing commits from members who can merge to end before do - target_project.add_master(member) + target_project.add_maintainer(member) sign_in(member) end diff --git a/spec/features/merge_request/user_cherry_picks_spec.rb b/spec/features/merge_request/user_cherry_picks_spec.rb index 61d1bdaa95a..c6ec3f08cc5 100644 --- a/spec/features/merge_request/user_cherry_picks_spec.rb +++ b/spec/features/merge_request/user_cherry_picks_spec.rb @@ -7,7 +7,7 @@ describe 'Merge request > User cherry-picks', :js do let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb index e1e70b6d260..8d2d4279d3c 100644 --- a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb +++ b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb @@ -32,7 +32,7 @@ describe 'Merge request < User customizes merge commit message', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/merge_request/user_merges_immediately_spec.rb b/spec/features/merge_request/user_merges_immediately_spec.rb index b16fc9bfc89..ea61f9675bc 100644 --- a/spec/features/merge_request/user_merges_immediately_spec.rb +++ b/spec/features/merge_request/user_merges_immediately_spec.rb @@ -19,7 +19,7 @@ describe 'Merge requests > User merges immediately', :js do context 'when there is active pipeline for merge request' do before do create(:ci_build, pipeline: pipeline) - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb index a045791f6b4..8372b61f872 100644 --- a/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb @@ -5,7 +5,7 @@ describe 'Merge request > User merges only if pipeline succeeds', :js do let(:project) { merge_request.target_project } before do - project.add_master(merge_request.author) + project.add_maintainer(merge_request.author) sign_in(merge_request.author) end diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb index db92a3504f3..53ed5d78598 100644 --- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb @@ -17,7 +17,7 @@ describe 'Merge request > User merges when pipeline succeeds', :js do end before do - project.add_master(user) + project.add_maintainer(user) end context 'when there is active pipeline for merge request' do diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index fa819cbc385..260c5f9c28b 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -14,7 +14,7 @@ describe 'Merge request > User posts notes', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index a0b9d6cb059..bf4d5396df9 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -19,7 +19,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do context 'no discussions' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) note.destroy visit_merge_request @@ -33,7 +33,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do context 'as authorized user' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit_merge_request end diff --git a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb index 0a8296bd722..428eb414274 100644 --- a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb +++ b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb @@ -19,7 +19,7 @@ describe 'Merge request > User sees avatars on diff notes', :js do let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user set_cookie('sidebar_collapsed', 'true') diff --git a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb index 726f35557a7..d7c784b14c5 100644 --- a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb +++ b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb @@ -18,7 +18,7 @@ describe 'Merge request > User sees closing issues message', :js do let(:merge_request_title) { 'Merge Request Title' } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_merge_request_path(project, merge_request) wait_for_requests diff --git a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb index 01115318370..46c21a2b155 100644 --- a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb +++ b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb @@ -6,7 +6,7 @@ describe 'Merge request > User sees deleted target branch', :js do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) DeleteBranchService.new(project, user).execute('feature') sign_in(user) visit project_merge_request_path(project, merge_request) diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb index 10390bd5864..7b8c3bacfe2 100644 --- a/spec/features/merge_request/user_sees_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_discussions_spec.rb @@ -6,7 +6,7 @@ describe 'Merge request > User sees discussions', :js do let(:merge_request) { create(:merge_request, source_project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_request/user_sees_empty_state_spec.rb b/spec/features/merge_request/user_sees_empty_state_spec.rb index a939c7e9001..482f31b02d4 100644 --- a/spec/features/merge_request/user_sees_empty_state_spec.rb +++ b/spec/features/merge_request/user_sees_empty_state_spec.rb @@ -5,7 +5,7 @@ describe 'Merge request > User sees empty state' do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb index 85df43df38e..f6b771facf8 100644 --- a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb @@ -6,7 +6,7 @@ describe 'Merge request > User sees merge button depending on unresolved discuss let!(:merge_request) { create(:merge_request_with_diff_notes, source_project: project, author: user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index 51a65407aec..b6b3844f2ae 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -10,8 +10,8 @@ describe 'Merge request > User sees merge widget', :js do let(:merge_request_in_only_mwps_project) { create(:merge_request, source_project: project_only_mwps) } before do - project.add_master(user) - project_only_mwps.add_master(user) + project.add_maintainer(user) + project_only_mwps.add_maintainer(user) sign_in(user) end @@ -275,7 +275,7 @@ describe 'Merge request > User sees merge widget', :js do let(:user2) { create(:user) } before do - project.add_master(user2) + project.add_maintainer(user2) sign_out(:user) sign_in(user2) merge_request.update(target_project: fork_project) diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb index a42c016392b..45cccbee63e 100644 --- a/spec/features/merge_request/user_sees_pipelines_spec.rb +++ b/spec/features/merge_request/user_sees_pipelines_spec.rb @@ -7,7 +7,7 @@ describe 'Merge request > User sees pipelines', :js do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end @@ -70,7 +70,7 @@ describe 'Merge request > User sees pipelines', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index 11e0806ba62..f42b4dcbb47 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -10,7 +10,7 @@ describe 'Merge request > User sees versions', :js do let!(:params) { {} } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit diffs_project_merge_request_path(project, merge_request, params) end diff --git a/spec/features/merge_request/user_sees_wip_help_message_spec.rb b/spec/features/merge_request/user_sees_wip_help_message_spec.rb index bc25243244e..92cc73ddf1f 100644 --- a/spec/features/merge_request/user_sees_wip_help_message_spec.rb +++ b/spec/features/merge_request/user_sees_wip_help_message_spec.rb @@ -5,7 +5,7 @@ describe 'Merge request > User sees WIP help message' do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb index ed6e29335d1..ae41cf90576 100644 --- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb +++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb @@ -11,7 +11,7 @@ describe 'Merge request > User selects branches for new MR', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb index 2e95a628013..dd860382daa 100644 --- a/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb +++ b/spec/features/merge_request/user_toggles_whitespace_changes_spec.rb @@ -6,7 +6,7 @@ describe 'Merge request > User toggles whitespace changes', :js do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit diffs_project_merge_request_path(project, merge_request) end diff --git a/spec/features/merge_request/user_uses_slash_commands_spec.rb b/spec/features/merge_request/user_uses_slash_commands_spec.rb index 83ad4b45b5a..b81478a481f 100644 --- a/spec/features/merge_request/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_request/user_uses_slash_commands_spec.rb @@ -21,7 +21,7 @@ describe 'Merge request > User uses quick actions', :js do let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } before do - project.add_master(user) + project.add_maintainer(user) end describe 'time tracking' do @@ -147,7 +147,7 @@ describe 'Merge request > User uses quick actions', :js do let(:new_url_opts) { { merge_request: { source_branch: 'feature' } } } before do - another_project.add_master(user) + another_project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb index 199ba7e87ad..bb327159cb0 100644 --- a/spec/features/merge_requests/user_mass_updates_spec.rb +++ b/spec/features/merge_requests/user_mass_updates_spec.rb @@ -6,7 +6,7 @@ describe 'Merge requests > User mass updates', :js do let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/merge_requests/user_squashes_merge_request_spec.rb b/spec/features/merge_requests/user_squashes_merge_request_spec.rb index da3d6772eeb..ec1153b7f7f 100644 --- a/spec/features/merge_requests/user_squashes_merge_request_spec.rb +++ b/spec/features/merge_requests/user_squashes_merge_request_spec.rb @@ -46,7 +46,7 @@ describe 'User squashes a merge request', :js do # Prevent source branch from being removed so we can use be_merged_to_root_ref # method to check if squash was performed or not allow_any_instance_of(MergeRequest).to receive(:force_remove_source_branch?).and_return(false) - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index b12aba2c263..a0673b12738 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -7,7 +7,7 @@ describe 'Milestone' do before do create(:group_member, group: group, user: user) - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb index 689196c2258..db797bb586f 100644 --- a/spec/features/profiles/user_visits_notifications_tab_spec.rb +++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb @@ -5,7 +5,7 @@ describe 'User visits the notifications tab', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(profile_notifications_path) end diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb index 713112477c8..2dc4547b2d8 100644 --- a/spec/features/profiles/user_visits_profile_spec.rb +++ b/spec/features/profiles/user_visits_profile_spec.rb @@ -29,7 +29,7 @@ describe 'User visits their profile' do let!(:project) do create(:project, :repository, namespace: group) do |project| create(:closed_issue_event, project: project) - project.add_master(user) + project.add_maintainer(user) end end diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb index 0ba2224359a..a93df3696d2 100644 --- a/spec/features/project_variables_spec.rb +++ b/spec/features/project_variables_spec.rb @@ -8,7 +8,7 @@ describe 'Project variables', :js do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) project.variables << variable visit page_path diff --git a/spec/features/projects/actve_tabs_spec.rb b/spec/features/projects/actve_tabs_spec.rb index ce5606b63ae..7c6110c533b 100644 --- a/spec/features/projects/actve_tabs_spec.rb +++ b/spec/features/projects/actve_tabs_spec.rb @@ -5,7 +5,7 @@ describe 'Project active tab' do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb b/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb index 12e07647ecd..4d860893abe 100644 --- a/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb +++ b/spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb @@ -6,7 +6,7 @@ describe 'User interacts with awards in an issue', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_issue_path(project, issue)) diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb index da87039ad44..e30b908c60d 100644 --- a/spec/features/projects/badges/list_spec.rb +++ b/spec/features/projects/badges/list_spec.rb @@ -4,7 +4,7 @@ describe 'list of badges' do before do user = create(:user) project = create(:project, :repository) - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_settings_ci_cd_path(project) end diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 7280d421cea..27589428896 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -144,7 +144,7 @@ describe 'File blob', :js do context 'Markdown file (stored in LFS)' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) Files::CreateService.new( project, @@ -237,7 +237,7 @@ describe 'File blob', :js do context 'PDF file' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) Files::CreateService.new( project, @@ -350,7 +350,7 @@ describe 'File blob', :js do context 'empty file' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) Files::CreateService.new( project, @@ -418,7 +418,7 @@ describe 'File blob', :js do context '.gitlab-ci.yml' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) Files::CreateService.new( project, @@ -446,7 +446,7 @@ describe 'File blob', :js do context '.gitlab/route-map.yml' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) Files::CreateService.new( project, @@ -494,7 +494,7 @@ describe 'File blob', :js do context '*.gemspec' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) Files::CreateService.new( project, diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 2657f5d999f..0e036b4ea68 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -134,11 +134,11 @@ describe 'Editing file blob', :js do end end - context 'as master' do + context 'as maintainer' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_edit_blob_path(project, tree_join(branch, file_path)) end diff --git a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb index 0b7988f6335..8a0b92190dd 100644 --- a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb +++ b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb @@ -24,9 +24,9 @@ describe 'User creates blob in new project', :js do end end - describe 'as a master' do + describe 'as a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'creating a file' diff --git a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb index 0be434a567b..0faf73db7da 100644 --- a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb +++ b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb @@ -6,7 +6,7 @@ describe 'New Branch Ref Dropdown', :js do let(:toggle) { find('.create-from .dropdown-menu-toggle') } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit new_project_branch_path(project) diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index b7ce1b9993a..97757e8da92 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -182,10 +182,10 @@ describe 'Branches' do end end - context 'logged in as master' do + context 'logged in as maintainer' do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) end describe 'Initial branches page' do diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb index f57647a348f..a65ca662350 100644 --- a/spec/features/projects/clusters/applications_spec.rb +++ b/spec/features/projects/clusters/applications_spec.rb @@ -7,7 +7,7 @@ describe 'Clusters Applications', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index bd8cb9b4b94..31e3ebf675d 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -7,7 +7,7 @@ describe 'Gcp Cluster', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) gitlab_sign_in(user) allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 } end diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index a49dd72a91f..babf47cc341 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -7,7 +7,7 @@ describe 'User Cluster', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) gitlab_sign_in(user) allow(Projects::ClustersController).to receive(:STATUS_POLLING_INTERVAL) { 100 } end diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index a7274c99704..91eac9c8278 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -7,7 +7,7 @@ describe 'Clusters', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) gitlab_sign_in(user) end diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index da0552441fe..bd254caddfb 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -5,7 +5,7 @@ describe 'project commit pipelines', :js do before do user = create(:user) - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb index 1df45865d6f..bc3c00dafe2 100644 --- a/spec/features/projects/commit/cherry_pick_spec.rb +++ b/spec/features/projects/commit/cherry_pick_spec.rb @@ -9,7 +9,7 @@ describe 'Cherry-pick Commits' do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) visit project_commit_path(project, master_pickable_commit.id) end diff --git a/spec/features/projects/commit/comments/user_adds_comment_spec.rb b/spec/features/projects/commit/comments/user_adds_comment_spec.rb index 53866c32c69..6397df086a7 100644 --- a/spec/features/projects/commit/comments/user_adds_comment_spec.rb +++ b/spec/features/projects/commit/comments/user_adds_comment_spec.rb @@ -62,7 +62,7 @@ describe "User adds a comment on a commit", :js do click_diff_line(sample_commit.line_code) expect(page).to have_css(".js-temp-notes-holder form.new-note") - .and have_css(".js-close-discussion-note-form", text: "Discard draft") + .and have_css(".js-close-discussion-note-form", text: "Cancel") # The `Cancel` button closes the current form. The page should not have any open forms after that. find(".js-close-discussion-note-form").click diff --git a/spec/features/projects/commit/diff_notes_spec.rb b/spec/features/projects/commit/diff_notes_spec.rb index 6d66889761f..e2aefa35fad 100644 --- a/spec/features/projects/commit/diff_notes_spec.rb +++ b/spec/features/projects/commit/diff_notes_spec.rb @@ -7,7 +7,7 @@ describe 'Commit diff', :js do let(:project) { create(:project, :public, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index 35ed6620548..23d8d606790 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -7,7 +7,7 @@ describe 'User browses commits' do let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index 7e863d9df32..69600884909 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -5,7 +5,7 @@ describe "Compare", :js do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb index 1552a3512dd..e12532e97fa 100644 --- a/spec/features/projects/deploy_keys_spec.rb +++ b/spec/features/projects/deploy_keys_spec.rb @@ -5,7 +5,7 @@ describe 'Project deploy keys', :js do let(:project) { create(:project_empty_repo) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb index 237157cd89d..df05625d105 100644 --- a/spec/features/projects/diffs/diff_show_spec.rb +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -24,7 +24,7 @@ describe 'Diff file viewer', :js do context 'Ruby file (stored in LFS)' do before do - project.add_master(project.creator) + project.add_maintainer(project.creator) @commit_id = Files::CreateService.new( project, diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index 0c34309c1f4..4c5dda29fee 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -102,8 +102,8 @@ describe 'Environment' do context 'with terminal' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do - context 'for project master' do - let(:role) { :master } + context 'for project maintainer' do + let(:role) { :maintainer } it 'it shows the terminal button' do expect(page).to have_terminal_button @@ -166,7 +166,8 @@ describe 'Environment' do end it 'allows to stop environment' do - click_link('Stop') + click_button('Stop') + click_button('Stop environment') # confirm modal expect(page).to have_content('close_app') end @@ -174,7 +175,7 @@ describe 'Environment' do context 'when user has no ability to stop environment' do it 'does not allow to stop environment' do - expect(page).to have_no_link('Stop') + expect(page).not_to have_button('Stop') end end @@ -182,7 +183,7 @@ describe 'Environment' do let(:role) { :reporter } it 'does not show stop button' do - expect(page).not_to have_link('Stop') + expect(page).not_to have_button('Stop') end end end @@ -192,7 +193,7 @@ describe 'Environment' do let(:environment) { create(:environment, project: project, state: :stopped) } it 'does not show stop button' do - expect(page).not_to have_link('Stop') + expect(page).not_to have_button('Stop') end end end @@ -230,7 +231,7 @@ describe 'Environment' do it 'user visits environment page' do visit_environment(environment) - expect(page).to have_link('Stop') + expect(page).to have_button('Stop') end it 'user deletes the branch with running environment' do @@ -242,7 +243,7 @@ describe 'Environment' do visit_environment(environment) - expect(page).to have_no_link('Stop') + expect(page).not_to have_button('Stop') end ## diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 9900c13095e..f0890018286 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -10,6 +10,10 @@ describe 'Environments page', :js do sign_in(user) end + def stop_button_selector + %q{button[data-original-title="Stop environment"]} + end + describe 'page tabs' do it 'shows "Available" and "Stopped" tab with links' do visit_environments(project) @@ -120,7 +124,7 @@ describe 'Environments page', :js do end it 'does not show stip button when environment is not stoppable' do - expect(page).not_to have_selector('.stop-env-link') + expect(page).not_to have_selector(stop_button_selector) end end @@ -178,7 +182,7 @@ describe 'Environments page', :js do end it 'shows a stop button' do - expect(page).not_to have_selector('.stop-env-link') + expect(page).not_to have_selector(stop_button_selector) end it 'does not show external link button' do @@ -211,22 +215,22 @@ describe 'Environments page', :js do end it 'shows a stop button' do - expect(page).to have_selector('.stop-env-link') + expect(page).to have_selector(stop_button_selector) end context 'when user is a reporter' do let(:role) { :reporter } it 'does not show stop button' do - expect(page).not_to have_selector('.stop-env-link') + expect(page).not_to have_selector(stop_button_selector) end end end context 'when kubernetes terminal is available' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do - context 'for project master' do - let(:role) { :master } + context 'for project maintainer' do + let(:role) { :maintainer } it 'shows the terminal button' do expect(page).to have_terminal_button diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index b0eb7c5b42a..ab16fdee883 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -8,7 +8,7 @@ describe 'Edit Project Settings' do describe 'project features visibility selectors', :js do before do - project.add_master(member) + project.add_maintainer(member) sign_in(member) end @@ -165,7 +165,7 @@ describe 'Edit Project Settings' do describe 'repository visibility', :js do before do - project.add_master(member) + project.add_maintainer(member) sign_in(member) visit edit_project_path(project) end diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index b410199fd1f..ac6c8c337fa 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -2,16 +2,16 @@ require 'spec_helper' describe 'Projects > Files > Project owner creates a license file', :js do let(:project) { create(:project, :repository) } - let(:project_master) { project.owner } + let(:project_maintainer) { project.owner } before do - project.repository.delete_file(project_master, 'LICENSE', + project.repository.delete_file(project_maintainer, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') - sign_in(project_master) + sign_in(project_maintainer) visit project_path(project) end - it 'project master creates a license file manually from a template' do + it 'project maintainer creates a license file manually from a template' do visit project_tree_path(project, project.repository.root_ref) find('.add-to-tree').click click_link 'New file' @@ -35,7 +35,7 @@ describe 'Projects > Files > Project owner creates a license file', :js do expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") end - it 'project master creates a license file from the "Add license" link' do + it 'project maintainer creates a license file from the "Add license" link' do click_link 'Add License' expect(page).to have_content('New file') diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index 53d8ace7c94..801291c1f77 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' describe 'Projects > Files > Project owner sees a link to create a license file in empty project', :js do let(:project) { create(:project_empty_repo) } - let(:project_master) { project.owner } + let(:project_maintainer) { project.owner } before do - sign_in(project_master) + sign_in(project_maintainer) end - it 'project master creates a license file from a template' do + it 'project maintainer creates a license file from a template' do visit project_path(project) click_on 'Add License' expect(page).to have_content('New file') diff --git a/spec/features/projects/files/template_selector_menu_spec.rb b/spec/features/projects/files/template_selector_menu_spec.rb index b7e1e172af9..6b313824acd 100644 --- a/spec/features/projects/files/template_selector_menu_spec.rb +++ b/spec/features/projects/files/template_selector_menu_spec.rb @@ -5,7 +5,7 @@ describe 'Template selector menu', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/projects/files/user_creates_files_spec.rb b/spec/features/projects/files/user_creates_files_spec.rb index 208cc8d81f7..d4dda43c823 100644 --- a/spec/features/projects/files/user_creates_files_spec.rb +++ b/spec/features/projects/files/user_creates_files_spec.rb @@ -12,7 +12,7 @@ describe 'Projects > Files > User creates files' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/files/user_deletes_files_spec.rb b/spec/features/projects/files/user_deletes_files_spec.rb index 36d3e001a64..0e9f83a16ce 100644 --- a/spec/features/projects/files/user_deletes_files_spec.rb +++ b/spec/features/projects/files/user_deletes_files_spec.rb @@ -17,7 +17,7 @@ describe 'Projects > Files > User deletes files' do context 'when an user has write access' do before do - project.add_master(user) + project.add_maintainer(user) visit(project_tree_path_root_ref) end diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index dc6e4fd27cb..ccc1bc1bc10 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -31,7 +31,7 @@ describe 'Projects > Files > User edits files' do context 'when an user has write access' do before do - project.add_master(user) + project.add_maintainer(user) visit(project_tree_path_root_ref) end diff --git a/spec/features/projects/files/user_find_file_spec.rb b/spec/features/projects/files/user_find_file_spec.rb index df405e70dd4..e2d881b34d2 100644 --- a/spec/features/projects/files/user_find_file_spec.rb +++ b/spec/features/projects/files/user_find_file_spec.rb @@ -6,7 +6,7 @@ describe 'User find project file' do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) visit project_tree_path(project, project.repository.root_ref) end diff --git a/spec/features/projects/files/user_reads_pipeline_status_spec.rb b/spec/features/projects/files/user_reads_pipeline_status_spec.rb index 2d0b447913e..ff0aa933a3e 100644 --- a/spec/features/projects/files/user_reads_pipeline_status_spec.rb +++ b/spec/features/projects/files/user_reads_pipeline_status_spec.rb @@ -7,7 +7,7 @@ describe 'user reads pipeline status', :js do let(:x110_pipeline) { create_pipeline('x1.1.0', 'failed') } before do - project.add_master(user) + project.add_maintainer(user) project.repository.add_tag(user, 'x1.1.0', 'v1.1.0') v110_pipeline diff --git a/spec/features/projects/files/user_replaces_files_spec.rb b/spec/features/projects/files/user_replaces_files_spec.rb index 9ac3417b671..3a81e77c4ba 100644 --- a/spec/features/projects/files/user_replaces_files_spec.rb +++ b/spec/features/projects/files/user_replaces_files_spec.rb @@ -19,7 +19,7 @@ describe 'Projects > Files > User replaces files' do context 'when an user has write access' do before do - project.add_master(user) + project.add_maintainer(user) visit(project_tree_path_root_ref) end diff --git a/spec/features/projects/files/user_uploads_files_spec.rb b/spec/features/projects/files/user_uploads_files_spec.rb index 8b212faa29d..af3fc528a20 100644 --- a/spec/features/projects/files/user_uploads_files_spec.rb +++ b/spec/features/projects/files/user_uploads_files_spec.rb @@ -14,7 +14,7 @@ describe 'Projects > Files > User uploads files' do let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index 1743b1e083f..cd5fef8238e 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -129,11 +129,11 @@ describe 'Project fork' do end end - context 'master in group' do + context 'maintainer in group' do let(:group) { create(:group) } before do - group.add_master(user) + group.add_maintainer(user) end it 'allows user to fork project to group or to user namespace' do diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb index 335174b7729..9665f1755d6 100644 --- a/spec/features/projects/graph_spec.rb +++ b/spec/features/projects/graph_spec.rb @@ -6,7 +6,7 @@ describe 'Project Graph', :js do let(:branch_name) { 'master' } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/hook_logs/user_reads_log_spec.rb b/spec/features/projects/hook_logs/user_reads_log_spec.rb index c3bc35565f6..086cd4b9f03 100644 --- a/spec/features/projects/hook_logs/user_reads_log_spec.rb +++ b/spec/features/projects/hook_logs/user_reads_log_spec.rb @@ -6,7 +6,7 @@ describe 'Hook logs' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index 9cd4af2de80..a57edc394f9 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -8,7 +8,7 @@ describe 'issuable templates', :js do let(:issue_form_location) { '#content-body .issuable-details .detail-page-description' } before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index ce0b38b7239..50e957bf12b 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -8,7 +8,7 @@ describe 'User browses a job', :js do let!(:build) { create(:ci_build, :success, :trace_artifact, :coverage, pipeline: pipeline) } before do - project.add_master(user) + project.add_maintainer(user) project.enable_ci sign_in(user) diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb index 786ec327b92..08786fe1630 100644 --- a/spec/features/projects/jobs/user_browses_jobs_spec.rb +++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb @@ -7,7 +7,7 @@ describe 'User browses jobs' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) project.enable_ci project.update_attribute(:build_coverage_regex, /Coverage (\d+)%/) diff --git a/spec/features/projects/labels/user_creates_labels_spec.rb b/spec/features/projects/labels/user_creates_labels_spec.rb index 9fd7f3ee775..c71b04fea09 100644 --- a/spec/features/projects/labels/user_creates_labels_spec.rb +++ b/spec/features/projects/labels/user_creates_labels_spec.rb @@ -18,7 +18,7 @@ describe "User creates labels" do context "in project" do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(new_project_label_path(project)) @@ -69,7 +69,7 @@ describe "User creates labels" do before do create(:label, project: project, title: "bug") # Create label for `project` (not `another_project`) project. - another_project.add_master(user) + another_project.add_maintainer(user) sign_in(user) visit(new_project_label_path(another_project)) diff --git a/spec/features/projects/labels/user_edits_labels_spec.rb b/spec/features/projects/labels/user_edits_labels_spec.rb index d1041ff5c1e..0708bbd40ce 100644 --- a/spec/features/projects/labels/user_edits_labels_spec.rb +++ b/spec/features/projects/labels/user_edits_labels_spec.rb @@ -6,7 +6,7 @@ describe "User edits labels" do set(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(edit_project_label_path(project, label)) diff --git a/spec/features/projects/labels/user_removes_labels_spec.rb b/spec/features/projects/labels/user_removes_labels_spec.rb index efa74015c6e..b0ce03a1c31 100644 --- a/spec/features/projects/labels/user_removes_labels_spec.rb +++ b/spec/features/projects/labels/user_removes_labels_spec.rb @@ -5,7 +5,7 @@ describe "User removes labels" do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb index 19e52294a38..b3ed725f602 100644 --- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb +++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb @@ -6,7 +6,7 @@ describe 'Projects > Members > Anonymous user sees members' do let(:project) { create(:project, :public) } before do - project.add_master(user) + project.add_maintainer(user) create(:project_group_link, project: project, group: group) end diff --git a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb index 7bc53345ddf..bb475ea95e5 100644 --- a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb @@ -12,8 +12,8 @@ describe 'Projects > Members > Group member cannot request access to his group p expect(page).not_to have_content 'Request Access' end - it 'master does not see the request access button' do - group.add_master(user) + it 'maintainer does not see the request access button' do + group.add_maintainer(user) login_and_visit_project_page(user) expect(page).not_to have_content 'Request Access' diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb index b65c46b345f..c0b5d943e96 100644 --- a/spec/features/projects/members/groups_with_access_list_spec.rb +++ b/spec/features/projects/members/groups_with_access_list_spec.rb @@ -6,7 +6,7 @@ describe 'Projects > Members > Groups with access list', :js do let(:project) { create(:project, :public) } before do - project.add_master(user) + project.add_maintainer(user) @group_link = create(:project_group_link, project: project, group: group) sign_in(user) diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 90f09bf6264..26de6fb33fd 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -1,16 +1,16 @@ require 'spec_helper' -describe 'Projects > Members > Master adds member with expiration date', :js do +describe 'Projects > Members > Maintainer adds member with expiration date', :js do include Select2Helper include ActiveSupport::Testing::TimeHelpers - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:project) { create(:project) } let!(:new_member) { create(:user) } before do - project.add_master(master) - sign_in(master) + project.add_maintainer(maintainer) + sign_in(maintainer) end it 'expiration date is displayed in the members list' do diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index 112b06c047d..adc8202cde7 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe 'Projects > Members > Master manages access requests' do - it_behaves_like 'Master manages access requests' do +describe 'Projects > Members > Maintainer manages access requests' do + it_behaves_like 'Maintainer manages access requests' do let(:entity) { create(:project, :public, :access_requestable) } let(:members_page_path) { project_project_members_path(entity) } end diff --git a/spec/features/projects/members/share_with_group_spec.rb b/spec/features/projects/members/share_with_group_spec.rb index b126f0c6cb1..c6d85e5d22f 100644 --- a/spec/features/projects/members/share_with_group_spec.rb +++ b/spec/features/projects/members/share_with_group_spec.rb @@ -4,7 +4,7 @@ describe 'Project > Members > Share with Group', :js do include Select2Helper include ActionView::Helpers::DateHelper - let(:master) { create(:user) } + let(:maintainer) { create(:user) } describe 'Share with group lock' do shared_examples 'the project can be shared with groups' do @@ -27,8 +27,8 @@ describe 'Project > Members > Share with Group', :js do let(:project) { create(:project, namespace: create(:group)) } before do - project.add_master(master) - sign_in(master) + project.add_maintainer(maintainer) + sign_in(maintainer) end context 'when the group has "Share with group lock" disabled' do @@ -65,8 +65,8 @@ describe 'Project > Members > Share with Group', :js do let(:project) { create(:project, namespace: subgroup) } before do - project.add_master(master) - sign_in(master) + project.add_maintainer(maintainer) + sign_in(maintainer) end context 'when the root_group has "Share with group lock" disabled' do @@ -112,8 +112,8 @@ describe 'Project > Members > Share with Group', :js do end before do - project.add_master(master) - sign_in(master) + project.add_maintainer(maintainer) + sign_in(maintainer) visit project_settings_members_path(project) @@ -142,11 +142,11 @@ describe 'Project > Members > Share with Group', :js do let(:project) { create(:project) } before do - project.add_master(master) - sign_in(master) + project.add_maintainer(maintainer) + sign_in(maintainer) - create(:group).add_owner(master) - create(:group).add_owner(master) + create(:group).add_owner(maintainer) + create(:group).add_owner(maintainer) visit project_settings_members_path(project) @@ -174,10 +174,10 @@ describe 'Project > Members > Share with Group', :js do let!(:project) { create(:project, namespace: nested_group) } before do - project.add_master(master) - sign_in(master) - group.add_master(master) - group_to_share_with.add_master(master) + project.add_maintainer(maintainer) + sign_in(maintainer) + group.add_maintainer(maintainer) + group_to_share_with.add_maintainer(maintainer) end it 'the groups dropdown does not show ancestors', :nested_groups do diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb index 1e1071348c3..220775b514d 100644 --- a/spec/features/projects/members/sorting_spec.rb +++ b/spec/features/projects/members/sorting_spec.rb @@ -1,20 +1,20 @@ require 'spec_helper' describe 'Projects > Members > Sorting' do - let(:master) { create(:user, name: 'John Doe') } + let(:maintainer) { create(:user, name: 'John Doe') } let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) } - let(:project) { create(:project, namespace: master.namespace, creator: master) } + let(:project) { create(:project, namespace: maintainer.namespace, creator: maintainer) } before do create(:project_member, :developer, user: developer, project: project, created_at: 3.days.ago) - sign_in(master) + sign_in(maintainer) end it 'sorts alphabetically by default' do visit_members_list(sort: nil) - expect(first_member).to include(master.name) + expect(first_member).to include(maintainer.name) expect(second_member).to include(developer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending') end @@ -23,14 +23,14 @@ describe 'Projects > Members > Sorting' do visit_members_list(sort: :access_level_asc) expect(first_member).to include(developer.name) - expect(second_member).to include(master.name) + expect(second_member).to include(maintainer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Access level, ascending') end it 'sorts by access level descending' do visit_members_list(sort: :access_level_desc) - expect(first_member).to include(master.name) + expect(first_member).to include(maintainer.name) expect(second_member).to include(developer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Access level, descending') end @@ -38,7 +38,7 @@ describe 'Projects > Members > Sorting' do it 'sorts by last joined' do visit_members_list(sort: :last_joined) - expect(first_member).to include(master.name) + expect(first_member).to include(maintainer.name) expect(second_member).to include(developer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Last joined') end @@ -47,14 +47,14 @@ describe 'Projects > Members > Sorting' do visit_members_list(sort: :oldest_joined) expect(first_member).to include(developer.name) - expect(second_member).to include(master.name) + expect(second_member).to include(maintainer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Oldest joined') end it 'sorts by name ascending' do visit_members_list(sort: :name_asc) - expect(first_member).to include(master.name) + expect(first_member).to include(maintainer.name) expect(second_member).to include(developer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending') end @@ -63,14 +63,14 @@ describe 'Projects > Members > Sorting' do visit_members_list(sort: :name_desc) expect(first_member).to include(developer.name) - expect(second_member).to include(master.name) + expect(second_member).to include(maintainer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Name, descending') end it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do visit_members_list(sort: :recent_sign_in) - expect(first_member).to include(master.name) + expect(first_member).to include(maintainer.name) expect(second_member).to include(developer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in') end @@ -79,7 +79,7 @@ describe 'Projects > Members > Sorting' do visit_members_list(sort: :oldest_sign_in) expect(first_member).to include(developer.name) - expect(second_member).to include(master.name) + expect(second_member).to include(maintainer.name) expect(page).to have_css('.member-sort-dropdown .dropdown-toggle-text', text: 'Oldest sign in') end diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index 5599cc9bf1b..50ba67f0ffc 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Projects > Members > User requests access', :js do let(:user) { create(:user) } let(:project) { create(:project, :public, :access_requestable, :repository) } - let(:master) { project.owner } + let(:maintainer) { project.owner } before do sign_in(user) @@ -20,7 +20,7 @@ describe 'Projects > Members > User requests access', :js do it 'user can request access to a project' do perform_enqueued_jobs { click_link 'Request Access' } - expect(ActionMailer::Base.deliveries.last.to).to eq [master.notification_email] + expect(ActionMailer::Base.deliveries.last.to).to eq [maintainer.notification_email] expect(ActionMailer::Base.deliveries.last.subject).to eq "Request to join the #{project.full_name} project" expect(project.requesters.exists?(user_id: user)).to be_truthy diff --git a/spec/features/projects/merge_requests/user_closes_merge_request_spec.rb b/spec/features/projects/merge_requests/user_closes_merge_request_spec.rb index b257f447439..2d12d690151 100644 --- a/spec/features/projects/merge_requests/user_closes_merge_request_spec.rb +++ b/spec/features/projects/merge_requests/user_closes_merge_request_spec.rb @@ -6,7 +6,7 @@ describe 'User closes a merge requests', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(merge_request_path(merge_request)) diff --git a/spec/features/projects/merge_requests/user_comments_on_commit_spec.rb b/spec/features/projects/merge_requests/user_comments_on_commit_spec.rb index 0a952cfc2a9..8ea358bcc70 100644 --- a/spec/features/projects/merge_requests/user_comments_on_commit_spec.rb +++ b/spec/features/projects/merge_requests/user_comments_on_commit_spec.rb @@ -9,7 +9,7 @@ describe 'User comments on a commit', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_commit_path(project, sample_commit.id)) diff --git a/spec/features/projects/merge_requests/user_comments_on_diff_spec.rb b/spec/features/projects/merge_requests/user_comments_on_diff_spec.rb index 1828b60fec7..441b080bee5 100644 --- a/spec/features/projects/merge_requests/user_comments_on_diff_spec.rb +++ b/spec/features/projects/merge_requests/user_comments_on_diff_spec.rb @@ -11,7 +11,7 @@ describe 'User comments on a diff', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(diffs_project_merge_request_path(project, merge_request)) @@ -31,7 +31,7 @@ describe 'User comments on a diff', :js do page.within('.files > div:nth-child(3)') do expect(page).to have_content('Line is wrong') - find('.js-toggle-diff-comments').click + find('.js-btn-vue-toggle-comments').click expect(page).not_to have_content('Line is wrong') end @@ -64,7 +64,7 @@ describe 'User comments on a diff', :js do # Hide the comment. page.within('.files > div:nth-child(3)') do - find('.js-toggle-diff-comments').click + find('.js-btn-vue-toggle-comments').click expect(page).not_to have_content('Line is wrong') end @@ -77,7 +77,7 @@ describe 'User comments on a diff', :js do # Show the comment. page.within('.files > div:nth-child(3)') do - find('.js-toggle-diff-comments').click + find('.js-btn-vue-toggle-comments').click end # Now both the comments should be shown. diff --git a/spec/features/projects/merge_requests/user_comments_on_merge_request_spec.rb b/spec/features/projects/merge_requests/user_comments_on_merge_request_spec.rb index f90aaba3caf..69bdab85d81 100644 --- a/spec/features/projects/merge_requests/user_comments_on_merge_request_spec.rb +++ b/spec/features/projects/merge_requests/user_comments_on_merge_request_spec.rb @@ -8,7 +8,7 @@ describe 'User comments on a merge request', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(merge_request_path(merge_request)) diff --git a/spec/features/projects/merge_requests/user_creates_merge_request_spec.rb b/spec/features/projects/merge_requests/user_creates_merge_request_spec.rb index 1f21ef7b382..38b4e4a6d1b 100644 --- a/spec/features/projects/merge_requests/user_creates_merge_request_spec.rb +++ b/spec/features/projects/merge_requests/user_creates_merge_request_spec.rb @@ -8,7 +8,7 @@ describe "User creates a merge request", :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/merge_requests/user_edits_merge_request_spec.rb b/spec/features/projects/merge_requests/user_edits_merge_request_spec.rb index 3d19a2923b9..7de0f9daac6 100644 --- a/spec/features/projects/merge_requests/user_edits_merge_request_spec.rb +++ b/spec/features/projects/merge_requests/user_edits_merge_request_spec.rb @@ -8,7 +8,7 @@ describe 'User edits a merge request', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(edit_project_merge_request_path(project, merge_request)) diff --git a/spec/features/projects/merge_requests/user_manages_subscription_spec.rb b/spec/features/projects/merge_requests/user_manages_subscription_spec.rb index f55eb5c6664..68a835e7f77 100644 --- a/spec/features/projects/merge_requests/user_manages_subscription_spec.rb +++ b/spec/features/projects/merge_requests/user_manages_subscription_spec.rb @@ -6,7 +6,7 @@ describe 'User manages subscription', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(merge_request_path(merge_request)) diff --git a/spec/features/projects/merge_requests/user_reopens_merge_request_spec.rb b/spec/features/projects/merge_requests/user_reopens_merge_request_spec.rb index ba3c9789da1..745b4537e72 100644 --- a/spec/features/projects/merge_requests/user_reopens_merge_request_spec.rb +++ b/spec/features/projects/merge_requests/user_reopens_merge_request_spec.rb @@ -6,7 +6,7 @@ describe 'User reopens a merge requests', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(merge_request_path(merge_request)) diff --git a/spec/features/projects/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/projects/merge_requests/user_sorts_merge_requests_spec.rb index 305658f1b5d..e401933aed2 100644 --- a/spec/features/projects/merge_requests/user_sorts_merge_requests_spec.rb +++ b/spec/features/projects/merge_requests/user_sorts_merge_requests_spec.rb @@ -9,7 +9,7 @@ describe 'User sorts merge requests' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_merge_requests_path(project)) diff --git a/spec/features/projects/merge_requests/user_views_open_merge_request_spec.rb b/spec/features/projects/merge_requests/user_views_open_merge_request_spec.rb index 3aac93eaf7c..6ac495aa03d 100644 --- a/spec/features/projects/merge_requests/user_views_open_merge_request_spec.rb +++ b/spec/features/projects/merge_requests/user_views_open_merge_request_spec.rb @@ -31,7 +31,7 @@ describe 'User views an open merge request' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(edit_project_merge_request_path(project, merge_request)) diff --git a/spec/features/projects/milestones/user_interacts_with_labels_spec.rb b/spec/features/projects/milestones/user_interacts_with_labels_spec.rb index f6a82f80d65..a6d58be7b13 100644 --- a/spec/features/projects/milestones/user_interacts_with_labels_spec.rb +++ b/spec/features/projects/milestones/user_interacts_with_labels_spec.rb @@ -11,7 +11,7 @@ describe 'User interacts with labels' do let(:label_enhancement) { create(:label, project: project, title: 'enhancement') } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) issue1.labels << [label_bug, label_feature] diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index f23ec11a458..bbe08ff83ff 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -25,6 +25,22 @@ describe 'New project' do expect(page).to have_link('GitLab export') end + describe 'manifest import option' do + before do + visit new_project_path + + find('#import-project-tab').click + end + + context 'when using postgres', :postgresql do + it { expect(page).to have_link('Manifest file') } + end + + context 'when using mysql', :mysql do + it { expect(page).not_to have_link('Manifest file') } + end + end + context 'Visibility level selector', :js do Gitlab::VisibilityLevel.options.each do |key, level| it "sets selector to #{key}" do @@ -94,7 +110,7 @@ describe 'New project' do let(:subgroup) { create(:group, parent: group) } before do - group.add_master(user) + group.add_maintainer(user) visit new_project_path(namespace_id: subgroup.id) end @@ -201,5 +217,16 @@ describe 'New project' do expect(current_path).to eq new_import_google_code_path end end + + context 'from manifest file', :postgresql do + before do + first('.import_manifest').click + end + + it 'shows import instructions' do + expect(page).to have_content('Manifest file import') + expect(current_path).to eq new_import_manifest_path + end + end end end diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 6bf65e16291..831f22a0e69 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Pages' do let(:project) { create(:project) } let(:user) { create(:user) } - let(:role) { :master } + let(:role) { :maintainer } before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb index 220b3529c59..ee6b67b2188 100644 --- a/spec/features/projects/pipeline_schedules_spec.rb +++ b/spec/features/projects/pipeline_schedules_spec.rb @@ -9,9 +9,9 @@ describe 'Pipeline Schedules', :js do let(:scope) { nil } let!(:user) { create(:user) } - context 'logged in as master' do + context 'logged in as maintainer' do before do - project.add_master(user) + project.add_maintainer(user) gitlab_sign_in(user) end diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 7d47e342e92..4a83bcc3efb 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -595,7 +595,7 @@ describe 'Pipelines', :js do before do create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master') - project.add_master(user) + project.add_maintainer(user) visit project_pipelines_path(project) end diff --git a/spec/features/projects/remote_mirror_spec.rb b/spec/features/projects/remote_mirror_spec.rb index 97db4a2b8f2..5259a8942dc 100644 --- a/spec/features/projects/remote_mirror_spec.rb +++ b/spec/features/projects/remote_mirror_spec.rb @@ -7,7 +7,7 @@ describe 'Project remote mirror', :feature do describe 'On a project', :js do before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/projects/services/user_activates_asana_spec.rb b/spec/features/projects/services/user_activates_asana_spec.rb index db836d2985c..c44e07dd3b4 100644 --- a/spec/features/projects/services/user_activates_asana_spec.rb +++ b/spec/features/projects/services/user_activates_asana_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Asana' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_assembla_spec.rb b/spec/features/projects/services/user_activates_assembla_spec.rb index f099b332785..9c3884a7c74 100644 --- a/spec/features/projects/services/user_activates_assembla_spec.rb +++ b/spec/features/projects/services/user_activates_assembla_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Assembla' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb b/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb index a00c2e0ad99..19573565265 100644 --- a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb +++ b/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Atlassian Bamboo CI' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_emails_on_push_spec.rb b/spec/features/projects/services/user_activates_emails_on_push_spec.rb index 3769875b29c..cc55f7b2060 100644 --- a/spec/features/projects/services/user_activates_emails_on_push_spec.rb +++ b/spec/features/projects/services/user_activates_emails_on_push_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Emails on push' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_flowdock_spec.rb b/spec/features/projects/services/user_activates_flowdock_spec.rb index 5298d8acaf5..f981b7e9da9 100644 --- a/spec/features/projects/services/user_activates_flowdock_spec.rb +++ b/spec/features/projects/services/user_activates_flowdock_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Flowdock' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_hipchat_spec.rb b/spec/features/projects/services/user_activates_hipchat_spec.rb index a9bf16642c7..2f5313c91f9 100644 --- a/spec/features/projects/services/user_activates_hipchat_spec.rb +++ b/spec/features/projects/services/user_activates_hipchat_spec.rb @@ -5,7 +5,7 @@ describe 'User activates HipChat' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_irker_spec.rb b/spec/features/projects/services/user_activates_irker_spec.rb index 435663c818f..4c8e321b411 100644 --- a/spec/features/projects/services/user_activates_irker_spec.rb +++ b/spec/features/projects/services/user_activates_irker_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Irker (IRC gateway)' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_issue_tracker_spec.rb b/spec/features/projects/services/user_activates_issue_tracker_spec.rb index e9502178bd7..7cd5b12802b 100644 --- a/spec/features/projects/services/user_activates_issue_tracker_spec.rb +++ b/spec/features/projects/services/user_activates_issue_tracker_spec.rb @@ -15,7 +15,7 @@ describe 'User activates issue tracker', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_settings_integrations_path(project) diff --git a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb index 1048803fde8..28d83a8b961 100644 --- a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb +++ b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb @@ -5,7 +5,7 @@ describe 'User activates JetBrains TeamCity CI' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_jira_spec.rb b/spec/features/projects/services/user_activates_jira_spec.rb index 429128ec096..08e1855d034 100644 --- a/spec/features/projects/services/user_activates_jira_spec.rb +++ b/spec/features/projects/services/user_activates_jira_spec.rb @@ -17,7 +17,7 @@ describe 'User activates Jira', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_settings_integrations_path(project) diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb index d4a6417290d..25b74cc481d 100644 --- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb @@ -8,7 +8,7 @@ describe 'Setup Mattermost slash commands', :js do before do stub_mattermost_setting(enabled: mattermost_enabled) - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit edit_project_service_path(project, service) end diff --git a/spec/features/projects/services/user_activates_packagist_spec.rb b/spec/features/projects/services/user_activates_packagist_spec.rb index b0cc818f093..756e9b33c07 100644 --- a/spec/features/projects/services/user_activates_packagist_spec.rb +++ b/spec/features/projects/services/user_activates_packagist_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Packagist' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_pivotaltracker_spec.rb b/spec/features/projects/services/user_activates_pivotaltracker_spec.rb index d5d109ba48b..1d6b19e0b0c 100644 --- a/spec/features/projects/services/user_activates_pivotaltracker_spec.rb +++ b/spec/features/projects/services/user_activates_pivotaltracker_spec.rb @@ -5,7 +5,7 @@ describe 'User activates PivotalTracker' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_prometheus_spec.rb b/spec/features/projects/services/user_activates_prometheus_spec.rb index 33f884eb148..61361c8a2e3 100644 --- a/spec/features/projects/services/user_activates_prometheus_spec.rb +++ b/spec/features/projects/services/user_activates_prometheus_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Prometheus' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_pushover_spec.rb b/spec/features/projects/services/user_activates_pushover_spec.rb index 9b7e8d62792..24612ee1457 100644 --- a/spec/features/projects/services/user_activates_pushover_spec.rb +++ b/spec/features/projects/services/user_activates_pushover_spec.rb @@ -5,7 +5,7 @@ describe 'User activates Pushover' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/services/user_activates_slack_notifications_spec.rb b/spec/features/projects/services/user_activates_slack_notifications_spec.rb index 727b1fe2d11..24b5d5259db 100644 --- a/spec/features/projects/services/user_activates_slack_notifications_spec.rb +++ b/spec/features/projects/services/user_activates_slack_notifications_spec.rb @@ -6,7 +6,7 @@ describe 'User activates Slack notifications' do let(:project) { create(:project, slack_service: service) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb index f540b76c784..08cfddf7993 100644 --- a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb @@ -6,7 +6,7 @@ describe 'Slack slash commands' do let(:service) { project.create_slack_slash_commands_service } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit edit_project_service_path(project, service) end diff --git a/spec/features/projects/services/user_views_services_spec.rb b/spec/features/projects/services/user_views_services_spec.rb index 5c5e8b66642..e9c8cf0fe34 100644 --- a/spec/features/projects/services/user_views_services_spec.rb +++ b/spec/features/projects/services/user_views_services_spec.rb @@ -5,7 +5,7 @@ describe 'User views services' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_settings_integrations_path(project)) diff --git a/spec/features/projects/settings/forked_project_settings_spec.rb b/spec/features/projects/settings/forked_project_settings_spec.rb index a4d1b78b83b..df33d215602 100644 --- a/spec/features/projects/settings/forked_project_settings_spec.rb +++ b/spec/features/projects/settings/forked_project_settings_spec.rb @@ -7,8 +7,8 @@ describe 'Projects > Settings > For a forked project', :js do let(:forked_project) { fork_project(original_project, user) } before do - original_project.add_master(user) - forked_project.add_master(user) + original_project.add_maintainer(user) + forked_project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb index 5178d63050e..8745ff72df0 100644 --- a/spec/features/projects/settings/integration_settings_spec.rb +++ b/spec/features/projects/settings/integration_settings_spec.rb @@ -21,8 +21,8 @@ describe 'Projects > Settings > Integration settings' do end end - context 'for master' do - let(:role) { :master } + context 'for maintainer' do + let(:role) { :maintainer } context 'Webhooks' do let(:hook) { create(:project_hook, :all_events_enabled, enable_ssl_verification: true, project: project) } diff --git a/spec/features/projects/settings/lfs_settings_spec.rb b/spec/features/projects/settings/lfs_settings_spec.rb index 342be1d2a9d..befb306b48d 100644 --- a/spec/features/projects/settings/lfs_settings_spec.rb +++ b/spec/features/projects/settings/lfs_settings_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Projects > Settings > LFS settings' do let(:project) { create(:project) } let(:user) { create(:user) } - let(:role) { :master } + let(:role) { :maintainer } context 'LFS enabled setting' do before do @@ -13,8 +13,8 @@ describe 'Projects > Settings > LFS settings' do project.add_role(user, role) end - context 'for master' do - let(:role) { :master } + context 'for maintainer' do + let(:role) { :maintainer } it 'displays the correct elements', :js do visit edit_project_path(project) diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index cfdae246c09..742ecf82c38 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -21,8 +21,8 @@ describe "Projects > Settings > Pipelines settings" do end end - context 'for master' do - let(:role) { :master } + context 'for maintainer' do + let(:role) { :maintainer } it 'be allowed to change' do visit project_settings_ci_cd_path(project) diff --git a/spec/features/projects/settings/project_badges_spec.rb b/spec/features/projects/settings/project_badges_spec.rb index e53da997c1d..2ec94274f80 100644 --- a/spec/features/projects/settings/project_badges_spec.rb +++ b/spec/features/projects/settings/project_badges_spec.rb @@ -12,7 +12,7 @@ describe 'Project Badges' do let!(:group_badge) { create(:group_badge, group: group) } before do - group.add_master(user) + group.add_maintainer(user) sign_in(user) visit(project_settings_badges_path(project)) diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index f085e1aa50a..a0f5b234ebc 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -20,8 +20,8 @@ describe 'Projects > Settings > Repository settings' do end end - context 'for master' do - let(:role) { :master } + context 'for maintainer' do + let(:role) { :maintainer } context 'Deploy Keys', :js do let(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) } @@ -124,7 +124,7 @@ describe 'Projects > Settings > Repository settings' do let(:user2) { create(:user) } before do - project.add_master(user2) + project.add_maintainer(user2) visit project_settings_repository_path(project) end diff --git a/spec/features/projects/settings/user_archives_project_spec.rb b/spec/features/projects/settings/user_archives_project_spec.rb index 38c8a8c2468..5008eab4d39 100644 --- a/spec/features/projects/settings/user_archives_project_spec.rb +++ b/spec/features/projects/settings/user_archives_project_spec.rb @@ -4,7 +4,7 @@ describe 'Projects > Settings > User archives a project' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/projects/settings/user_changes_avatar_spec.rb b/spec/features/projects/settings/user_changes_avatar_spec.rb index 2dcc79d8a12..64335163016 100644 --- a/spec/features/projects/settings/user_changes_avatar_spec.rb +++ b/spec/features/projects/settings/user_changes_avatar_spec.rb @@ -5,7 +5,7 @@ describe 'Projects > Settings > User changes avatar' do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb index 71a077039b7..ecfb49b9efe 100644 --- a/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb +++ b/spec/features/projects/settings/user_interacts_with_deploy_keys_spec.rb @@ -50,7 +50,7 @@ describe "User interacts with deploy keys", :js do before do create(:deploy_keys_project, project: another_project, deploy_key: deploy_key) - another_project.add_master(user) + another_project.add_maintainer(user) end it "shows deploy keys" do @@ -110,7 +110,7 @@ describe "User interacts with deploy keys", :js do before do create(:deploy_keys_project, project: another_project, deploy_key: deploy_key) - another_project.add_master(user) + another_project.add_maintainer(user) end it_behaves_like "attaches a key" diff --git a/spec/features/projects/settings/user_manages_group_links_spec.rb b/spec/features/projects/settings/user_manages_group_links_spec.rb index 92ce2ca83c7..2f1824d7849 100644 --- a/spec/features/projects/settings/user_manages_group_links_spec.rb +++ b/spec/features/projects/settings/user_manages_group_links_spec.rb @@ -9,10 +9,10 @@ describe 'Projects > Settings > User manages group links' do let(:group_market) { create(:group, name: 'Market', path: 'market') } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) - share_link = project.project_group_links.new(group_access: Gitlab::Access::MASTER) + share_link = project.project_group_links.new(group_access: Gitlab::Access::MAINTAINER) share_link.group_id = group_ops.id share_link.save! diff --git a/spec/features/projects/settings/user_manages_project_members_spec.rb b/spec/features/projects/settings/user_manages_project_members_spec.rb index d3003753ae6..b8ca11d53f0 100644 --- a/spec/features/projects/settings/user_manages_project_members_spec.rb +++ b/spec/features/projects/settings/user_manages_project_members_spec.rb @@ -9,7 +9,7 @@ describe 'Projects > Settings > User manages project members' do let(:user_mike) { create(:user, name: 'Mike') } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user_dmitriy) sign_in(user) end @@ -30,7 +30,7 @@ describe 'Projects > Settings > User manages project members' do end it 'imports a team from another project' do - project2.add_master(user) + project2.add_maintainer(user) project2.add_reporter(user_mike) visit(project_project_members_path(project)) @@ -54,7 +54,7 @@ describe 'Projects > Settings > User manages project members' do group.add_owner(user) group.add_developer(user_dmitriy) - share_link = project.project_group_links.new(group_access: Gitlab::Access::MASTER) + share_link = project.project_group_links.new(group_access: Gitlab::Access::MAINTAINER) share_link.group_id = group.id share_link.save! diff --git a/spec/features/projects/settings/user_transfers_a_project_spec.rb b/spec/features/projects/settings/user_transfers_a_project_spec.rb index 96b7cf1f93b..2fdbc04fa62 100644 --- a/spec/features/projects/settings/user_transfers_a_project_spec.rb +++ b/spec/features/projects/settings/user_transfers_a_project_spec.rb @@ -10,7 +10,7 @@ describe 'Projects > Settings > User transfers a project', :js do sign_in(user) end - def transfer_project(project, group) + def transfer_project(project, group, confirm: true) visit edit_project_path(project) page.within('.js-project-transfer-form') do @@ -21,6 +21,8 @@ describe 'Projects > Settings > User transfers a project', :js do click_button('Transfer project') + return unless confirm + fill_in 'confirm_name_input', with: project.name click_button 'Confirm' @@ -28,6 +30,11 @@ describe 'Projects > Settings > User transfers a project', :js do wait_for_requests end + it 'focuses on the confirmation field' do + transfer_project(project, group, confirm: false) + expect(page).to have_selector '#confirm_name_input:focus' + end + it 'allows transferring a project to a group' do old_path = project_path(project) transfer_project(project, group) diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index 2ec6990313f..1fbc108697f 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -59,12 +59,12 @@ describe 'Projects > Settings > Visibility settings', :js do end end - context 'as master' do - let(:master_user) { create(:user) } + context 'as maintainer' do + let(:maintainer_user) { create(:user) } before do - project.add_master(master_user) - sign_in(master_user) + project.add_maintainer(maintainer_user) + sign_in(maintainer_user) visit edit_project_path(project) end diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb index 7b9242f0631..0405e21a0d7 100644 --- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb +++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb @@ -38,9 +38,9 @@ describe 'Projects > Show > User sees setup shortcut buttons' do end end - describe 'as a master' do + describe 'as a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_path(project) @@ -138,10 +138,10 @@ describe 'Projects > Show > User sees setup shortcut buttons' do end end - describe 'as a master' do + describe 'as a maintainer' do before do allow_any_instance_of(AutoDevopsHelper).to receive(:show_auto_devops_callout?).and_return(false) - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 2388feeb980..6d8a72dd6a3 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -16,7 +16,7 @@ describe 'Projects > Snippets > Create Snippet', :js do context 'when a user is authenticated' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_snippets_path(project) diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index 004ac55b656..3cc797277dd 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -6,7 +6,7 @@ describe 'Projects > Snippets > Project snippet', :js do let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb index 01cf9740d1f..d82e350e0f7 100644 --- a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb +++ b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb @@ -6,7 +6,7 @@ describe 'Projects > Snippets > User comments on a snippet', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_snippet_path(project, snippet)) diff --git a/spec/features/projects/snippets/user_deletes_snippet_spec.rb b/spec/features/projects/snippets/user_deletes_snippet_spec.rb index e64837ad59e..2bd8bb9d551 100644 --- a/spec/features/projects/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/projects/snippets/user_deletes_snippet_spec.rb @@ -6,7 +6,7 @@ describe 'Projects > Snippets > User deletes a snippet' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_snippet_path(project, snippet)) diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb index eaedbbf32b6..33f77d55f89 100644 --- a/spec/features/projects/snippets/user_updates_snippet_spec.rb +++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb @@ -6,7 +6,7 @@ describe 'Projects > Snippets > User updates a snippet' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_snippet_path(project, snippet)) diff --git a/spec/features/projects/snippets/user_views_snippets_spec.rb b/spec/features/projects/snippets/user_views_snippets_spec.rb index 376b76e0001..1243db9d9f7 100644 --- a/spec/features/projects/snippets/user_views_snippets_spec.rb +++ b/spec/features/projects/snippets/user_views_snippets_spec.rb @@ -8,7 +8,7 @@ describe 'Projects > Snippets > User views snippets' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_snippets_path(project)) diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb index eb2d3ff50a0..50e7e934cf6 100644 --- a/spec/features/projects/sub_group_issuables_spec.rb +++ b/spec/features/projects/sub_group_issuables_spec.rb @@ -7,7 +7,7 @@ describe 'Subgroup Issuables', :js, :nested_groups do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user end diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb index d0902bce7f3..d3aa4912099 100644 --- a/spec/features/projects/tree/create_directory_spec.rb +++ b/spec/features/projects/tree/create_directory_spec.rb @@ -5,7 +5,7 @@ describe 'Multi-file editor new directory', :js do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_tree_path(project, :master) @@ -22,9 +22,7 @@ describe 'Multi-file editor new directory', :js do end it 'creates directory in current directory' do - find('.add-to-tree').click - - click_link('New directory') + all('.ide-tree-header button').last.click page.within('.modal') do find('.form-control').set('folder name') @@ -32,9 +30,7 @@ describe 'Multi-file editor new directory', :js do click_button('Create directory') end - find('.add-to-tree').click - - click_link('New file') + first('.ide-tree-header button').click page.within('.modal-dialog') do find('.form-control').set('file name') diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb index 03a29fae0bd..f836783cbff 100644 --- a/spec/features/projects/tree/create_file_spec.rb +++ b/spec/features/projects/tree/create_file_spec.rb @@ -5,7 +5,7 @@ describe 'Multi-file editor new file', :js do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_path(project) @@ -22,9 +22,7 @@ describe 'Multi-file editor new file', :js do end it 'creates file in current directory' do - find('.add-to-tree').click - - click_link('New file') + first('.ide-tree-header button').click page.within('.modal') do find('.form-control').set('file name') diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb index dc59666ffce..9e15163fd72 100644 --- a/spec/features/projects/tree/tree_show_spec.rb +++ b/spec/features/projects/tree/tree_show_spec.rb @@ -5,7 +5,7 @@ describe 'Projects tree' do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_tree_path(project, 'master') diff --git a/spec/features/projects/tree/upload_file_spec.rb b/spec/features/projects/tree/upload_file_spec.rb index 804a4450ae2..dcf7d314f8e 100644 --- a/spec/features/projects/tree/upload_file_spec.rb +++ b/spec/features/projects/tree/upload_file_spec.rb @@ -7,7 +7,7 @@ describe 'Multi-file editor upload file', :js do let(:img_file) { File.join(Rails.root, 'spec', 'fixtures', 'dk.png') } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_tree_path(project, :master) @@ -24,14 +24,10 @@ describe 'Multi-file editor upload file', :js do end it 'uploads text file' do - find('.add-to-tree').click - # make the field visible so capybara can use it execute_script('document.querySelector("#file-upload").classList.remove("hidden")') attach_file('file-upload', txt_file) - find('.add-to-tree').click - expect(page).to have_selector('.multi-file-tab', text: 'doc_sample.txt') expect(find('.blob-editor-container .lines-content')['innerText']).to have_content(File.open(txt_file, &:readline)) end diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb index c8b3104b9fe..df9ee69aadb 100644 --- a/spec/features/projects/user_uses_shortcuts_spec.rb +++ b/spec/features/projects/user_uses_shortcuts_spec.rb @@ -5,7 +5,7 @@ describe 'User uses shortcuts', :js do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_path(project)) diff --git a/spec/features/projects/user_views_empty_project_spec.rb b/spec/features/projects/user_views_empty_project_spec.rb index 7b982301ffc..b7c0834d33a 100644 --- a/spec/features/projects/user_views_empty_project_spec.rb +++ b/spec/features/projects/user_views_empty_project_spec.rb @@ -15,9 +15,9 @@ describe 'User views an empty project' do end end - describe 'as a master' do + describe 'as a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'allowing push to default branch' diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb index 84ec32b3fac..a48ad94e9fa 100644 --- a/spec/features/projects/view_on_env_spec.rb +++ b/spec/features/projects/view_on_env_spec.rb @@ -7,7 +7,7 @@ describe 'View on environment', :js do let(:user) { project.creator } before do - project.add_master(user) + project.add_maintainer(user) end context 'when the branch has a route map' do diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 0bec5f185d6..ed5f8105487 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -14,7 +14,7 @@ describe 'Projects > Wiki > User previews markdown changes', :js do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index 733e6c89de7..830565620d6 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -4,7 +4,7 @@ describe "User creates wiki page" do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(project_wikis_path(project)) diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 2ccbc15b6da..2840d28cf30 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -4,7 +4,7 @@ describe 'User updates wiki page' do shared_examples 'wiki page user update' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb index 92b50169476..fb0ebe22bf7 100644 --- a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb @@ -4,7 +4,7 @@ describe 'Projects > Wiki > User views wiki in project page' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb index 1de7d9a56a8..0ef7f35f64a 100644 --- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_page_spec.rb @@ -11,7 +11,7 @@ describe 'User views a wiki page' do end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 8636d17f2c4..39b47d99040 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -151,10 +151,16 @@ describe 'Project' do before do sign_in(user) - project.add_master(user) + project.add_maintainer(user) visit edit_project_path(project) end + it 'focuses on the confirmation field' do + click_button 'Remove project' + + expect(page).to have_selector '#confirm_name_input:focus' + end + it 'removes a project' do expect { remove_with_confirm('Remove project', project.path) }.to change { Project.count }.by(-1) expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted." @@ -169,7 +175,7 @@ describe 'Project' do let(:project) { create(:forked_project_with_submodules) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user visit project_path(project) end @@ -198,7 +204,7 @@ describe 'Project' do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in user visit project_path(project) end diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 83a5f88f0b5..63c38a25f4b 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -28,9 +28,9 @@ describe 'Protected Branches', :js do end end - context 'logged in as master' do + context 'logged in as maintainer' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb index 9b6864eb90f..54ebda9dcab 100644 --- a/spec/features/reportable_note/commit_spec.rb +++ b/spec/features/reportable_note/commit_spec.rb @@ -7,7 +7,7 @@ describe 'Reportable note on commit', :js do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb index f5a1950e48e..bce1f7a3780 100644 --- a/spec/features/reportable_note/issue_spec.rb +++ b/spec/features/reportable_note/issue_spec.rb @@ -7,7 +7,7 @@ describe 'Reportable note on issue', :js do let!(:note) { create(:note_on_issue, noteable: issue, project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_issue_path(project, issue) diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb index 1f69257f7ed..d00324156c4 100644 --- a/spec/features/reportable_note/merge_request_spec.rb +++ b/spec/features/reportable_note/merge_request_spec.rb @@ -6,7 +6,7 @@ describe 'Reportable note on merge request', :js do let(:merge_request) { create(:merge_request, source_project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_merge_request_path(project, merge_request) diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb index 98ef50b78de..06218d9b286 100644 --- a/spec/features/reportable_note/snippets_spec.rb +++ b/spec/features/reportable_note/snippets_spec.rb @@ -5,7 +5,7 @@ describe 'Reportable note on snippets', :js do let(:project) { create(:project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 443c2b9acae..0c6cf3dc477 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -11,7 +11,7 @@ describe 'Runners' do let(:project) { create(:project) } before do - project.add_master(user) + project.add_maintainer(user) end it 'user can see a button to install runners on kubernetes clusters' do @@ -25,7 +25,7 @@ describe 'Runners' do let(:project) { create(:project) } before do - project.add_master(user) + project.add_maintainer(user) end context 'when a project_type runner is activated on the project' do @@ -125,7 +125,7 @@ describe 'Runners' do let!(:specific_runner) { create(:ci_runner, :project, projects: [another_project]) } before do - another_project.add_master(user) + another_project.add_maintainer(user) end it 'user enables and disables a specific runner' do @@ -165,7 +165,7 @@ describe 'Runners' do let(:project) { create(:project, shared_runners_enabled: false) } before do - project.add_master(user) + project.add_maintainer(user) end it 'user enables shared runners' do @@ -179,14 +179,14 @@ describe 'Runners' do context 'group runners in project settings' do before do - project.add_master(user) + project.add_maintainer(user) end let(:group) { create :group } context 'as project and group maintainer' do before do - group.add_master(user) + group.add_maintainer(user) end context 'project with a group but no group runner' do @@ -260,7 +260,7 @@ describe 'Runners' do context 'group runners in group settings' do let(:group) { create(:group) } before do - group.add_master(user) + group.add_maintainer(user) end context 'group with no runners' do diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb index 9e089c5a6cb..ecec2f3e043 100644 --- a/spec/features/search/user_searches_for_code_spec.rb +++ b/spec/features/search/user_searches_for_code_spec.rb @@ -6,7 +6,7 @@ describe 'User searches for code' do context 'when signed in' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb index d6120ff8517..4bff269f89e 100644 --- a/spec/features/search/user_searches_for_issues_spec.rb +++ b/spec/features/search/user_searches_for_issues_spec.rb @@ -8,7 +8,7 @@ describe 'User searches for issues', :js do context 'when signed in' do before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(search_path) diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb index 68e2f7a857d..75d44e413cb 100644 --- a/spec/features/search/user_searches_for_merge_requests_spec.rb +++ b/spec/features/search/user_searches_for_merge_requests_spec.rb @@ -7,7 +7,7 @@ describe 'User searches for merge requests', :js do let!(:merge_request2) { create(:merge_request, :simple, title: 'Bar', source_project: project, target_project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(search_path) diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb index fc6cd81eb68..7d52c4c8bcc 100644 --- a/spec/features/search/user_searches_for_milestones_spec.rb +++ b/spec/features/search/user_searches_for_milestones_spec.rb @@ -7,7 +7,7 @@ describe 'User searches for milestones', :js do let!(:milestone2) { create(:milestone, title: 'Bar', project: project) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(search_path) diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb index 5098fb49ee1..3ee753b7d23 100644 --- a/spec/features/search/user_searches_for_wiki_pages_spec.rb +++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb @@ -6,7 +6,7 @@ describe 'User searches for wiki pages', :js do let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, attrs: { title: 'test_wiki', content: 'Some Wiki content' }) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit(search_path) diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index 5067f0b0a49..51b32ba6c03 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -23,7 +23,7 @@ describe 'Internal Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -38,7 +38,7 @@ describe 'Internal Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -54,7 +54,7 @@ describe 'Internal Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -69,7 +69,7 @@ describe 'Internal Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -84,7 +84,7 @@ describe 'Internal Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_denied_for(:master).of(group) } + it { is_expected.to be_denied_for(:maintainer).of(group) } it { is_expected.to be_denied_for(:developer).of(group) } it { is_expected.to be_denied_for(:reporter).of(group) } it { is_expected.to be_denied_for(:guest).of(group) } diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index ff32413dc7e..4705cd12d23 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -23,7 +23,7 @@ describe 'Private Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -38,7 +38,7 @@ describe 'Private Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -54,7 +54,7 @@ describe 'Private Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -69,7 +69,7 @@ describe 'Private Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -84,7 +84,7 @@ describe 'Private Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_denied_for(:master).of(group) } + it { is_expected.to be_denied_for(:maintainer).of(group) } it { is_expected.to be_denied_for(:developer).of(group) } it { is_expected.to be_denied_for(:reporter).of(group) } it { is_expected.to be_denied_for(:guest).of(group) } diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index 16d114fb3f7..3a53c3c2bc7 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -23,7 +23,7 @@ describe 'Public Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -38,7 +38,7 @@ describe 'Public Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -54,7 +54,7 @@ describe 'Public Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -69,7 +69,7 @@ describe 'Public Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_allowed_for(:master).of(group) } + it { is_expected.to be_allowed_for(:maintainer).of(group) } it { is_expected.to be_allowed_for(:developer).of(group) } it { is_expected.to be_allowed_for(:reporter).of(group) } it { is_expected.to be_allowed_for(:guest).of(group) } @@ -84,7 +84,7 @@ describe 'Public Group access' do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(group) } - it { is_expected.to be_denied_for(:master).of(group) } + it { is_expected.to be_denied_for(:maintainer).of(group) } it { is_expected.to be_denied_for(:developer).of(group) } it { is_expected.to be_denied_for(:reporter).of(group) } it { is_expected.to be_denied_for(:guest).of(group) } diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index a7928857b7d..001e6c10eb2 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -17,7 +17,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -31,7 +31,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -45,7 +45,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -59,7 +59,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -73,7 +73,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -87,7 +87,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -101,7 +101,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -115,7 +115,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -130,7 +130,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -144,7 +144,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -158,7 +158,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -172,7 +172,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -187,7 +187,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -201,7 +201,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -215,7 +215,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -229,7 +229,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -243,7 +243,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -262,7 +262,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -281,7 +281,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -295,7 +295,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -309,7 +309,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -324,7 +324,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -343,7 +343,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -359,7 +359,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -381,7 +381,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -397,7 +397,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -419,7 +419,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -435,7 +435,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -450,7 +450,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -464,7 +464,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -479,7 +479,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -494,7 +494,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -508,7 +508,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -530,7 +530,7 @@ describe "Internal Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index a4396b20afd..c6618355eea 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -17,7 +17,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -31,7 +31,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -45,7 +45,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -59,7 +59,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -73,7 +73,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -87,7 +87,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -101,7 +101,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -115,7 +115,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -130,7 +130,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -144,7 +144,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -158,7 +158,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -172,7 +172,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -187,7 +187,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -201,7 +201,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -215,7 +215,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -234,7 +234,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -253,7 +253,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -267,7 +267,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -281,7 +281,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -308,7 +308,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -334,7 +334,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -362,7 +362,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -395,7 +395,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -425,7 +425,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -440,7 +440,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -455,7 +455,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -469,7 +469,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -483,7 +483,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -497,7 +497,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -511,7 +511,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -533,7 +533,7 @@ describe "Private Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index fccdeb0e5b7..3717dc13f1e 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -17,7 +17,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -31,7 +31,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -45,7 +45,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -59,7 +59,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -73,7 +73,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -87,7 +87,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -101,7 +101,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -115,7 +115,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -129,7 +129,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -144,7 +144,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -163,7 +163,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -179,7 +179,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -201,7 +201,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -217,7 +217,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -239,7 +239,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -255,7 +255,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -270,7 +270,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -284,7 +284,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -299,7 +299,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -314,7 +314,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -328,7 +328,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -344,7 +344,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -357,7 +357,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -371,7 +371,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -385,7 +385,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -400,7 +400,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -414,7 +414,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -428,7 +428,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -442,7 +442,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -456,7 +456,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -475,7 +475,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -494,7 +494,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -508,7 +508,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_denied_for(:developer).of(project) } it { is_expected.to be_denied_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -530,7 +530,7 @@ describe "Public Project Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb index d7dc99c0a57..b87eb86b88b 100644 --- a/spec/features/security/project/snippet/internal_access_spec.rb +++ b/spec/features/security/project/snippet/internal_access_spec.rb @@ -13,7 +13,7 @@ describe "Internal Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -27,7 +27,7 @@ describe "Internal Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -42,7 +42,7 @@ describe "Internal Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -56,7 +56,7 @@ describe "Internal Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -72,7 +72,7 @@ describe "Internal Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -86,7 +86,7 @@ describe "Internal Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb index 3ec1a388185..ead91d9a5fa 100644 --- a/spec/features/security/project/snippet/private_access_spec.rb +++ b/spec/features/security/project/snippet/private_access_spec.rb @@ -12,7 +12,7 @@ describe "Private Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -26,7 +26,7 @@ describe "Private Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -40,7 +40,7 @@ describe "Private Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -54,7 +54,7 @@ describe "Private Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb index 39b104bfe27..9bab3a474b8 100644 --- a/spec/features/security/project/snippet/public_access_spec.rb +++ b/spec/features/security/project/snippet/public_access_spec.rb @@ -14,7 +14,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -28,7 +28,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_denied_for(:guest).of(project) } @@ -43,7 +43,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -57,7 +57,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -71,7 +71,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -87,7 +87,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -101,7 +101,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } @@ -115,7 +115,7 @@ describe "Public Project Snippets Access" do it { is_expected.to be_allowed_for(:admin) } it { is_expected.to be_allowed_for(:owner).of(project) } - it { is_expected.to be_allowed_for(:master).of(project) } + it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } it { is_expected.to be_allowed_for(:guest).of(project) } diff --git a/spec/features/signed_commits_spec.rb b/spec/features/signed_commits_spec.rb index bc9443c6093..3d05474dca2 100644 --- a/spec/features/signed_commits_spec.rb +++ b/spec/features/signed_commits_spec.rb @@ -5,7 +5,7 @@ describe 'GPG signed commits', :js do it 'changes from unverified to verified when the user changes his email to match the gpg key' do user = create :user, email: 'unrelated.user@example.org' - project.add_master(user) + project.add_maintainer(user) Sidekiq::Testing.inline! do create :gpg_key, key: GpgHelpers::User1.public_key, user: user @@ -36,7 +36,7 @@ describe 'GPG signed commits', :js do it 'changes from unverified to verified when the user adds the missing gpg key' do user = create :user, email: GpgHelpers::User1.emails.first - project.add_master(user) + project.add_maintainer(user) sign_in(user) @@ -86,7 +86,7 @@ describe 'GPG signed commits', :js do before do user = create :user - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/tags/master_creates_tag_spec.rb b/spec/features/tags/master_creates_tag_spec.rb index b4e8253057b..db2970f3340 100644 --- a/spec/features/tags/master_creates_tag_spec.rb +++ b/spec/features/tags/master_creates_tag_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' -describe 'Master creates tag' do +describe 'Maintainer creates tag' do let(:user) { create(:user) } let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index 1443e259ed9..8d567e925ef 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' -describe 'Master deletes tag' do +describe 'Maintainer deletes tag' do let(:user) { create(:user) } let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_tags_path(project) end diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb index 4c0be6be96c..d8b5b3c4cc4 100644 --- a/spec/features/tags/master_updates_tag_spec.rb +++ b/spec/features/tags/master_updates_tag_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' -describe 'Master updates tag' do +describe 'Maintainer updates tag' do let(:user) { create(:user) } let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) visit project_tags_path(project) end diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb index 02ce0242614..3f4fe549f3e 100644 --- a/spec/features/tags/master_views_tags_spec.rb +++ b/spec/features/tags/master_views_tags_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' -describe 'Master views tags' do +describe 'Maintainer views tags' do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index 64d05c57d3c..9c9127980a1 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -65,7 +65,7 @@ describe 'Task Lists' do before do Warden.test_mode! - project.add_master(user) + project.add_maintainer(user) project.add_guest(user2) login_as(user) diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index 36dafccd186..919859c145a 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -10,8 +10,8 @@ describe 'Triggers', :js do sign_in(user) @project = create(:project) - @project.add_master(user) - @project.add_master(user2) + @project.add_maintainer(user) + @project.add_maintainer(user2) @project.add_guest(guest_user) visit project_settings_ci_cd_path(@project) diff --git a/spec/features/users/user_browses_projects_on_user_page_spec.rb b/spec/features/users/user_browses_projects_on_user_page_spec.rb index 5478e38ce70..6a9b281fb4c 100644 --- a/spec/features/users/user_browses_projects_on_user_page_spec.rb +++ b/spec/features/users/user_browses_projects_on_user_page_spec.rb @@ -4,19 +4,19 @@ describe 'Users > User browses projects on user page', :js do let!(:user) { create :user } let!(:private_project) do create :project, :private, name: 'private', namespace: user.namespace do |project| - project.add_master(user) + project.add_maintainer(user) end end let!(:internal_project) do create :project, :internal, name: 'internal', namespace: user.namespace do |project| - project.add_master(user) + project.add_maintainer(user) end end let!(:public_project) do create :project, :public, name: 'public', namespace: user.namespace do |project| - project.add_master(user) + project.add_maintainer(user) end end diff --git a/spec/finders/access_requests_finder_spec.rb b/spec/finders/access_requests_finder_spec.rb index 650f7229647..605777462bb 100644 --- a/spec/finders/access_requests_finder_spec.rb +++ b/spec/finders/access_requests_finder_spec.rb @@ -51,7 +51,7 @@ describe AccessRequestsFinder do context 'when current user can see access requests' do before do - project.add_master(user) + project.add_maintainer(user) group.add_owner(user) end @@ -78,7 +78,7 @@ describe AccessRequestsFinder do context 'when current user can see access requests' do before do - project.add_master(user) + project.add_maintainer(user) group.add_owner(user) end diff --git a/spec/finders/admin/projects_finder_spec.rb b/spec/finders/admin/projects_finder_spec.rb index 7901d5fee28..44cc8debd04 100644 --- a/spec/finders/admin/projects_finder_spec.rb +++ b/spec/finders/admin/projects_finder_spec.rb @@ -54,7 +54,7 @@ describe Admin::ProjectsFinder do context 'filter by visibility_level' do before do - private_project.add_master(user) + private_project.add_maintainer(user) end context 'private' do diff --git a/spec/finders/concerns/finder_with_cross_project_access_spec.rb b/spec/finders/concerns/finder_with_cross_project_access_spec.rb index c784fb87972..1ff65a8101b 100644 --- a/spec/finders/concerns/finder_with_cross_project_access_spec.rb +++ b/spec/finders/concerns/finder_with_cross_project_access_spec.rb @@ -25,7 +25,7 @@ describe FinderWithCrossProjectAccess do let!(:result) { create(:issue) } before do - result.project.add_master(user) + result.project.add_maintainer(user) end def expect_access_check_on_result diff --git a/spec/finders/contributed_projects_finder_spec.rb b/spec/finders/contributed_projects_finder_spec.rb index 60ea98e61c7..9155a8d6fe9 100644 --- a/spec/finders/contributed_projects_finder_spec.rb +++ b/spec/finders/contributed_projects_finder_spec.rb @@ -10,9 +10,9 @@ describe ContributedProjectsFinder do let!(:private_project) { create(:project, :private) } before do - private_project.add_master(source_user) + private_project.add_maintainer(source_user) private_project.add_developer(current_user) - public_project.add_master(source_user) + public_project.add_maintainer(source_user) create(:push_event, project: public_project, author: source_user) create(:push_event, project: private_project, author: source_user) diff --git a/spec/finders/environments_finder_spec.rb b/spec/finders/environments_finder_spec.rb index 3a8a1e7de74..3cd421f22eb 100644 --- a/spec/finders/environments_finder_spec.rb +++ b/spec/finders/environments_finder_spec.rb @@ -7,7 +7,7 @@ describe EnvironmentsFinder do let(:environment) { create(:environment, project: project) } before do - project.add_master(user) + project.add_maintainer(user) end context 'tagged deployment' do diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb index 63e15b365a4..f545da3aee4 100644 --- a/spec/finders/group_members_finder_spec.rb +++ b/spec/finders/group_members_finder_spec.rb @@ -9,9 +9,9 @@ describe GroupMembersFinder, '#execute' do let(:user4) { create(:user) } it 'returns members for top-level group' do - member1 = group.add_master(user1) - member2 = group.add_master(user2) - member3 = group.add_master(user3) + member1 = group.add_maintainer(user1) + member2 = group.add_maintainer(user2) + member3 = group.add_maintainer(user3) result = described_class.new(group).execute @@ -19,11 +19,11 @@ describe GroupMembersFinder, '#execute' do end it 'returns members for nested group', :nested_groups do - group.add_master(user2) + group.add_maintainer(user2) nested_group.request_access(user4) - member1 = group.add_master(user1) - member3 = nested_group.add_master(user2) - member4 = nested_group.add_master(user3) + member1 = group.add_maintainer(user1) + member3 = nested_group.add_maintainer(user2) + member4 = nested_group.add_maintainer(user3) result = described_class.new(nested_group).execute @@ -31,11 +31,11 @@ describe GroupMembersFinder, '#execute' do end it 'returns members for descendant groups if requested', :nested_groups do - member1 = group.add_master(user2) - member2 = group.add_master(user1) - nested_group.add_master(user2) - member3 = nested_group.add_master(user3) - member4 = nested_group.add_master(user4) + member1 = group.add_maintainer(user2) + member2 = group.add_maintainer(user1) + nested_group.add_maintainer(user2) + member3 = nested_group.add_maintainer(user3) + member4 = nested_group.add_maintainer(user4) result = described_class.new(group).execute(include_descendants: true) diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index 0a69c03e491..d6d95906f5e 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -17,16 +17,16 @@ describe GroupProjectsFinder do let!(:subgroup_private_project) { create(:project, :private, path: '7', group: subgroup) } before do - shared_project_1.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) - shared_project_2.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) - shared_project_3.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) + shared_project_1.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) + shared_project_2.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) + shared_project_3.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) end subject { finder.execute } describe 'with a group member current user' do before do - group.add_master(current_user) + group.add_maintainer(current_user) end context "only shared" do @@ -68,7 +68,7 @@ describe GroupProjectsFinder do describe 'without group member current_user' do before do - shared_project_2.add_master(current_user) + shared_project_2.add_maintainer(current_user) current_user.reload end @@ -93,8 +93,8 @@ describe GroupProjectsFinder do context "without external user" do before do - private_project.add_master(current_user) - subgroup_private_project.add_master(current_user) + private_project.add_maintainer(current_user) + subgroup_private_project.add_maintainer(current_user) end context 'with subgroups projects', :nested_groups do diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 74e91b02f0f..07a2fa86dd7 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -26,7 +26,7 @@ describe IssuesFinder do let(:issues) { described_class.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute } before(:context) do - project1.add_master(user) + project1.add_maintainer(user) project2.add_developer(user) project2.add_developer(user2) project3.add_developer(user) diff --git a/spec/finders/joined_groups_finder_spec.rb b/spec/finders/joined_groups_finder_spec.rb index 7f77a713b12..ae3e55f90f1 100644 --- a/spec/finders/joined_groups_finder_spec.rb +++ b/spec/finders/joined_groups_finder_spec.rb @@ -15,7 +15,7 @@ describe JoinedGroupsFinder do context 'without a user' do before do - public_group.add_master(profile_owner) + public_group.add_maintainer(profile_owner) end it 'only shows public groups from profile owner' do @@ -25,9 +25,9 @@ describe JoinedGroupsFinder do context "with a user" do before do - private_group.add_master(profile_owner) - internal_group.add_master(profile_owner) - public_group.add_master(profile_owner) + private_group.add_maintainer(profile_owner) + internal_group.add_maintainer(profile_owner) + public_group.add_maintainer(profile_owner) end context "when the profile visitor is in the private group" do @@ -64,7 +64,7 @@ describe JoinedGroupsFinder do context "if authorized" do before do - internal_group.add_master(profile_visitor) + internal_group.add_maintainer(profile_visitor) end it "shows internal groups if authorized" do diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb index 2fc5299b0f4..db48f00cd74 100644 --- a/spec/finders/members_finder_spec.rb +++ b/spec/finders/members_finder_spec.rb @@ -11,9 +11,9 @@ describe MembersFinder, '#execute' do it 'returns members for project and parent groups', :nested_groups do nested_group.request_access(user1) - member1 = group.add_master(user2) - member2 = nested_group.add_master(user3) - member3 = project.add_master(user4) + member1 = group.add_maintainer(user2) + member2 = nested_group.add_maintainer(user3) + member3 = project.add_maintainer(user4) result = described_class.new(project, user2).execute @@ -23,9 +23,9 @@ describe MembersFinder, '#execute' do it 'includes nested group members if asked', :nested_groups do project = create(:project, namespace: group) nested_group.request_access(user1) - member1 = group.add_master(user2) - member2 = nested_group.add_master(user3) - member3 = project.add_master(user4) + member1 = group.add_maintainer(user2) + member2 = nested_group.add_maintainer(user3) + member3 = project.add_maintainer(user4) result = described_class.new(project, user2).execute(include_descendants: true) diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index 669ec602f11..35d0eeda8f6 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -24,7 +24,7 @@ describe MergeRequestsFinder do let!(:merge_request5) { create(:merge_request, :simple, author: user, source_project: project4, target_project: project4) } before do - project1.add_master(user) + project1.add_maintainer(user) project2.add_developer(user) project3.add_developer(user) project2.add_developer(user2) @@ -142,7 +142,7 @@ describe MergeRequestsFinder do end before do - new_project.add_master(user) + new_project.add_maintainer(user) end it 'filters by created_after' do diff --git a/spec/finders/move_to_project_finder_spec.rb b/spec/finders/move_to_project_finder_spec.rb index e1faf3d569c..1511cb0e04c 100644 --- a/spec/finders/move_to_project_finder_spec.rb +++ b/spec/finders/move_to_project_finder_spec.rb @@ -8,7 +8,7 @@ describe MoveToProjectFinder do let(:guest_project) { create(:project) } let(:reporter_project) { create(:project) } let(:developer_project) { create(:project) } - let(:master_project) { create(:project) } + let(:maintainer_project) { create(:project) } subject { described_class.new(user) } @@ -23,9 +23,9 @@ describe MoveToProjectFinder do it 'returns projects equal or above Gitlab::Access::REPORTER ordered by id in descending order' do reporter_project.add_reporter(user) developer_project.add_developer(user) - master_project.add_master(user) + maintainer_project.add_maintainer(user) - expect(subject.execute(project).to_a).to eq([master_project, developer_project, reporter_project]) + expect(subject.execute(project).to_a).to eq([maintainer_project, developer_project, reporter_project]) end it 'does not include the source project' do @@ -57,9 +57,9 @@ describe MoveToProjectFinder do reporter_project.add_reporter(user) developer_project.add_developer(user) - master_project.add_master(user) + maintainer_project.add_maintainer(user) - expect(subject.execute(project).to_a).to eq([master_project, developer_project]) + expect(subject.execute(project).to_a).to eq([maintainer_project, developer_project]) end it 'returns projects after the given offset id' do @@ -67,9 +67,9 @@ describe MoveToProjectFinder do reporter_project.add_reporter(user) developer_project.add_developer(user) - master_project.add_master(user) + maintainer_project.add_maintainer(user) - expect(subject.execute(project, search: nil, offset_id: master_project.id).to_a).to eq([developer_project, reporter_project]) + expect(subject.execute(project, search: nil, offset_id: maintainer_project.id).to_a).to eq([developer_project, reporter_project]) expect(subject.execute(project, search: nil, offset_id: developer_project.id).to_a).to eq([reporter_project]) expect(subject.execute(project, search: nil, offset_id: reporter_project.id).to_a).to be_empty end @@ -84,10 +84,10 @@ describe MoveToProjectFinder do it 'returns projects matching a search query' do foo_project = create(:project) - foo_project.add_master(user) + foo_project.add_maintainer(user) wadus_project = create(:project, name: 'wadus') - wadus_project.add_master(user) + wadus_project.add_maintainer(user) expect(subject.execute(project).to_a).to eq([wadus_project, foo_project]) expect(subject.execute(project, search: 'wadus').to_a).to eq([wadus_project]) diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb index 232f35c86f9..b776e9d856a 100644 --- a/spec/finders/notes_finder_spec.rb +++ b/spec/finders/notes_finder_spec.rb @@ -5,7 +5,7 @@ describe NotesFinder do let(:project) { create(:project) } before do - project.add_master(user) + project.add_maintainer(user) end describe '#execute' do diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb index 0dfe6ba9c32..7931ad9b9f0 100644 --- a/spec/finders/projects_finder_spec.rb +++ b/spec/finders/projects_finder_spec.rb @@ -41,7 +41,7 @@ describe ProjectsFinder do describe 'with private projects' do before do - private_project.add_master(user) + private_project.add_maintainer(user) end it { is_expected.to match_array([public_project, internal_project, private_project]) } @@ -56,7 +56,7 @@ describe ProjectsFinder do describe 'filter by visibility_level' do before do - private_project.add_master(user) + private_project.add_maintainer(user) end context 'private' do diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb index 6061021d3b0..9747b9402a7 100644 --- a/spec/finders/todos_finder_spec.rb +++ b/spec/finders/todos_finder_spec.rb @@ -5,76 +5,12 @@ describe TodosFinder do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, namespace: group) } - let(:issue) { create(:issue, project: project) } - let(:merge_request) { create(:merge_request, source_project: project) } let(:finder) { described_class } before do group.add_developer(user) end - describe '#execute' do - context 'visibility' do - let(:private_group_access) { create(:group, :private) } - let(:private_group_hidden) { create(:group, :private) } - let(:public_project) { create(:project, :public) } - let(:private_project_hidden) { create(:project) } - let(:public_group) { create(:group) } - - let!(:todo1) { create(:todo, user: user, project: project, group: nil) } - let!(:todo2) { create(:todo, user: user, project: public_project, group: nil) } - let!(:todo3) { create(:todo, user: user, project: private_project_hidden, group: nil) } - let!(:todo4) { create(:todo, user: user, project: nil, group: group) } - let!(:todo5) { create(:todo, user: user, project: nil, group: private_group_access) } - let!(:todo6) { create(:todo, user: user, project: nil, group: private_group_hidden) } - let!(:todo7) { create(:todo, user: user, project: nil, group: public_group) } - - before do - private_group_access.add_developer(user) - end - - it 'returns only todos with a target a user has access to' do - todos = finder.new(user).execute - - expect(todos).to match_array([todo1, todo2, todo4, todo5, todo7]) - end - end - - context 'filtering' do - let!(:todo1) { create(:todo, user: user, project: project, target: issue) } - let!(:todo2) { create(:todo, user: user, group: group, target: merge_request) } - - it 'returns correct todos when filtered by a project' do - todos = finder.new(user, { project_id: project.id }).execute - - expect(todos).to match_array([todo1]) - end - - it 'returns correct todos when filtered by a group' do - todos = finder.new(user, { group_id: group.id }).execute - - expect(todos).to match_array([todo1, todo2]) - end - - it 'returns correct todos when filtered by a type' do - todos = finder.new(user, { type: 'Issue' }).execute - - expect(todos).to match_array([todo1]) - end - - context 'with subgroups', :nested_groups do - let(:subgroup) { create(:group, parent: group) } - let!(:todo3) { create(:todo, user: user, group: subgroup, target: issue) } - - it 'returns todos from subgroups when filtered by a group' do - todos = finder.new(user, { group_id: group.id }).execute - - expect(todos).to match_array([todo1, todo2, todo3]) - end - end - end - end - describe '#sort' do context 'by date' do let!(:todo1) { create(:todo, user: user, project: project) } diff --git a/spec/fixtures/aosp_manifest.xml b/spec/fixtures/aosp_manifest.xml new file mode 100644 index 00000000000..cfd0094b735 --- /dev/null +++ b/spec/fixtures/aosp_manifest.xml @@ -0,0 +1,685 @@ +<?xml version="1.0" encoding="UTF-8"?> +<manifest> + + <remote name="aosp" + fetch=".." + review="https://android-review.googlesource.com/" /> + <default revision="master" + remote="aosp" + sync-j="4" /> + + <project path="build/make" name="platform/build" groups="pdk" > + <copyfile src="core/root.mk" dest="Makefile" /> + <linkfile src="CleanSpec.mk" dest="build/CleanSpec.mk" /> + <linkfile src="buildspec.mk.default" dest="build/buildspec.mk.default" /> + <linkfile src="core" dest="build/core" /> + <linkfile src="envsetup.sh" dest="build/envsetup.sh" /> + <linkfile src="target" dest="build/target" /> + <linkfile src="tools" dest="build/tools" /> + </project> + <project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" /> + <project path="build/kati" name="platform/build/kati" groups="pdk,tradefed" /> + <project path="build/soong" name="platform/build/soong" groups="pdk,tradefed" > + <linkfile src="root.bp" dest="Android.bp" /> + <linkfile src="bootstrap.bash" dest="bootstrap.bash" /> + </project> + <project path="art" name="platform/art" groups="pdk" /> + <project path="bionic" name="platform/bionic" groups="pdk" /> + <project path="bootable/recovery" name="platform/bootable/recovery" groups="pdk" /> + <project path="compatibility/cdd" name="platform/compatibility/cdd" groups="pdk" /> + <project path="cts" name="platform/cts" groups="cts,pdk-cw-fs,pdk-fs" /> + <project path="dalvik" name="platform/dalvik" groups="pdk-cw-fs,pdk-fs" /> + <project path="developers/build" name="platform/developers/build" groups="developers" /> + <project path="developers/demos" name="platform/developers/demos" groups="developers" /> + <project path="developers/samples/android" name="platform/developers/samples/android" groups="developers" /> + <project path="development" name="platform/development" groups="developers,pdk-cw-fs,pdk-fs" /> + <project path="device/asus/fugu" name="device/asus/fugu" groups="device,fugu,broadcom_pdk" /> + <project path="device/asus/fugu-kernel" name="device/asus/fugu-kernel" groups="device,fugu,broadcom_pdk" clone-depth="1" /> + <project path="device/common" name="device/common" groups="pdk-cw-fs,pdk" /> + <project path="device/generic/arm64" name="device/generic/arm64" groups="pdk" /> + <project path="device/generic/armv7-a-neon" name="device/generic/armv7-a-neon" groups="pdk" /> + <project path="device/generic/car" name="device/generic/car" groups="pdk" /> + <project path="device/generic/common" name="device/generic/common" groups="pdk" /> + <project path="device/generic/goldfish" name="device/generic/goldfish" groups="pdk" /> + <project path="device/generic/goldfish-opengl" name="device/generic/goldfish-opengl" groups="pdk" /> + <project path="device/generic/mini-emulator-arm64" name="device/generic/mini-emulator-arm64" groups="pdk" /> + <project path="device/generic/mini-emulator-armv7-a-neon" name="device/generic/mini-emulator-armv7-a-neon" groups="pdk" /> + <project path="device/generic/mini-emulator-x86" name="device/generic/mini-emulator-x86" groups="pdk" /> + <project path="device/generic/mini-emulator-x86_64" name="device/generic/mini-emulator-x86_64" groups="pdk" /> + <project path="device/generic/qemu" name="device/generic/qemu" groups="pdk" /> + <project path="device/generic/uml" name="device/generic/uml" groups="device,pdk" /> + <project path="device/generic/x86" name="device/generic/x86" groups="pdk" /> + <project path="device/generic/x86_64" name="device/generic/x86_64" groups="pdk" /> + <project path="device/google/accessory/arduino" name="device/google/accessory/arduino" groups="device,pdk" /> + <project path="device/google/accessory/demokit" name="device/google/accessory/demokit" groups="device,pdk" /> + <project path="device/google/atv" name="device/google/atv" groups="device,broadcom_pdk,generic_fs,pdk" /> + <project path="device/google/contexthub" name="device/google/contexthub" groups="device,marlin,pdk" /> + <project path="device/google/cuttlefish" name="device/google/cuttlefish" groups="device" /> + <project path="device/google/cuttlefish_common" name="device/google/cuttlefish_common" groups="device" /> + <project path="device/google/cuttlefish_kernel" name="device/google/cuttlefish_kernel" groups="device" clone-depth="1" /> + <project path="device/google/dragon" name="device/google/dragon" groups="device,dragon" /> + <project path="device/google/dragon-kernel" name="device/google/dragon-kernel" groups="device,dragon" clone-depth="1" /> + <project path="device/google/marlin" name="device/google/marlin" groups="device,marlin,pdk" /> + <project path="device/google/marlin-kernel" name="device/google/marlin-kernel" groups="device,marlin,pdk" clone-depth="1" /> + <project path="device/google/muskie" name="device/google/muskie" groups="device,muskie" /> + <project path="device/google/taimen" name="device/google/taimen" groups="device,taimen" /> + <project path="device/google/vrservices" name="device/google/vrservices" groups="pdk" clone-depth="1" /> + <project path="device/google/wahoo" name="device/google/wahoo" groups="device,wahoo" /> + <project path="device/google/wahoo-kernel" name="device/google/wahoo-kernel" groups="device,wahoo" clone-depth="1" /> + <project path="device/huawei/angler" name="device/huawei/angler" groups="device,angler,broadcom_pdk" /> + <project path="device/huawei/angler-kernel" name="device/huawei/angler-kernel" groups="device,angler,broadcom_pdk" clone-depth="1" /> + <project path="device/lge/bullhead" name="device/lge/bullhead" groups="device,bullhead" /> + <project path="device/lge/bullhead-kernel" name="device/lge/bullhead-kernel" groups="device,bullhead" clone-depth="1" /> + <project path="device/linaro/bootloader/arm-trusted-firmware" name="device/linaro/bootloader/arm-trusted-firmware" /> + <project path="device/linaro/bootloader/edk2" name="device/linaro/bootloader/edk2" /> + <project path="device/linaro/bootloader/OpenPlatformPkg" name="device/linaro/bootloader/OpenPlatformPkg" /> + <project path="device/linaro/hikey" name="device/linaro/hikey" groups="device,hikey,pdk" /> + <project path="device/linaro/hikey-kernel" name="device/linaro/hikey-kernel" groups="device,hikey,pdk" clone-depth="1" /> + <project path="device/sample" name="device/sample" groups="pdk" /> + <project path="external/aac" name="platform/external/aac" groups="pdk" /> + <project path="external/abi-compliance-checker" name="platform/external/abi-compliance-checker" groups="pdk" /> + <project path="external/abi-dumper" name="platform/external/abi-dumper" groups="pdk" /> + <project path="external/adt-infra" name="platform/external/adt-infra" groups="adt-infra,notdefault,pdk-fs" /> + <project path="external/android-clat" name="platform/external/android-clat" groups="pdk" /> + <project path="external/androidplot" name="platform/external/androidplot" groups="pdk" /> + <project path="external/annotation-tools" name="platform/external/annotation-tools" groups="pdk" /> + <project path="external/ant-glob" name="platform/external/ant-glob" groups="pdk" /> + <project path="external/antlr" name="platform/external/antlr" groups="pdk" /> + <project path="external/apache-commons-math" name="platform/external/apache-commons-math" groups="pdk" /> + <project path="external/apache-harmony" name="platform/external/apache-harmony" groups="pdk" /> + <project path="external/apache-http" name="platform/external/apache-http" groups="pdk" /> + <project path="external/apache-xml" name="platform/external/apache-xml" groups="pdk" /> + <project path="external/archive-patcher" name="platform/external/archive-patcher" groups="pdk" /> + <project path="external/arm-neon-tests" name="platform/external/arm-neon-tests" groups="vendor" /> + <project path="external/autotest" name="platform/external/autotest" groups="pdk-fs" /> + <project path="external/avb" name="platform/external/avb" groups="pdk" /> + <project path="external/bart" name="platform/external/bart" groups="pdk" /> + <project path="external/blktrace" name="platform/external/blktrace" groups="pdk" /> + <project path="external/boringssl" name="platform/external/boringssl" groups="pdk" /> + <project path="external/bouncycastle" name="platform/external/bouncycastle" groups="pdk" /> + <project path="external/brotli" name="platform/external/brotli" groups="pdk" /> + <project path="external/bsdiff" name="platform/external/bsdiff" groups="pdk" /> + <project path="external/bzip2" name="platform/external/bzip2" groups="pdk" /> + <project path="external/caliper" name="platform/external/caliper" groups="pdk" /> + <project path="external/cblas" name="platform/external/cblas" groups="pdk" /> + <project path="external/chromium-libpac" name="platform/external/chromium-libpac" groups="pdk" /> + <project path="external/chromium-trace" name="platform/external/chromium-trace" groups="pdk" /> + <project path="external/chromium-webview" name="platform/external/chromium-webview" groups="pdk" clone-depth="1" /> + <project path="external/clang" name="platform/external/clang" groups="pdk" /> + <project path="external/cldr" name="platform/external/cldr" groups="pdk" /> + <project path="external/cmockery" name="platform/external/cmockery" groups="pdk" /> + <project path="external/cn-cbor" name="platform/external/cn-cbor" groups="pdk" /> + <project path="external/compiler-rt" name="platform/external/compiler-rt" groups="pdk" /> + <project path="external/conscrypt" name="platform/external/conscrypt" groups="pdk" /> + <project path="external/crcalc" name="platform/external/crcalc" groups="pdk" /> + <project path="external/cros/system_api" name="platform/external/cros/system_api" groups="pdk" /> + <project path="external/curl" name="platform/external/curl" groups="pdk" /> + <project path="external/dagger2" name="platform/external/dagger2" groups="pdk" /> + <project path="external/deqp" name="platform/external/deqp" groups="pdk-fs" /> + <project path="external/desugar" name="platform/external/desugar" groups="pdk" /> + <project path="external/devlib" name="platform/external/devlib" groups="pdk" /> + <project path="external/dexmaker" name="platform/external/dexmaker" groups="pdk" /> + <project path="external/dhcpcd-6.8.2" name="platform/external/dhcpcd-6.8.2" groups="pdk" /> + <project path="external/dlmalloc" name="platform/external/dlmalloc" groups="pdk" /> + <project path="external/dng_sdk" name="platform/external/dng_sdk" groups="pdk" /> + <project path="external/dnsmasq" name="platform/external/dnsmasq" groups="pdk" /> + <project path="external/doclava" name="platform/external/doclava" groups="pdk" /> + <project path="external/dokka" name="platform/external/dokka" groups="pdk" /> + <project path="external/drm_hwcomposer" name="platform/external/drm_hwcomposer" groups="drm_hwcomposer,pdk-fs" /> + <project path="external/droiddriver" name="platform/external/droiddriver" groups="pdk" /> + <project path="external/drrickorang" name="platform/external/drrickorang" groups="pdk" /> + <project path="external/dtc" name="platform/external/dtc" groups="pdk"/> + <project path="external/e2fsprogs" name="platform/external/e2fsprogs" groups="pdk" /> + <project path="external/easymock" name="platform/external/easymock" groups="pdk" /> + <project path="external/eigen" name="platform/external/eigen" groups="pdk" /> + <project path="external/elfutils" name="platform/external/elfutils" groups="pdk" /> + <project path="external/emma" name="platform/external/emma" groups="pdk" /> + <project path="external/error_prone" name="platform/external/error_prone" groups="pdk" /> + <project path="external/esd" name="platform/external/esd" groups="pdk" /> + <project path="external/expat" name="platform/external/expat" groups="pdk" /> + <project path="external/eyes-free" name="platform/external/eyes-free" groups="pdk" /> + <project path="external/f2fs-tools" name="platform/external/f2fs-tools" groups="pdk" /> + <project path="external/fdlibm" name="platform/external/fdlibm" groups="pdk" /> + <project path="external/fec" name="platform/external/fec" groups="pdk" /> + <project path="external/flac" name="platform/external/flac" groups="pdk" /> + <project path="external/flatbuffers" name="platform/external/flatbuffers" groups="pdk" /> + <project path="external/fonttools" name="platform/external/fonttools" groups="pdk" /> + <project path="external/freetype" name="platform/external/freetype" groups="pdk" /> + <project path="external/fsck_msdos" name="platform/external/fsck_msdos" groups="pdk" /> + <project path="external/gemmlowp" name="platform/external/gemmlowp" groups="pdk" /> + <project path="external/gflags" name="platform/external/gflags" groups="pdk" /> + <project path="external/giflib" name="platform/external/giflib" groups="pdk,qcom_msm8x26" /> + <project path="external/glide" name="platform/external/glide" groups="pdk" /> + <project path="external/golang-protobuf" name="platform/external/golang-protobuf" groups="pdk" /> + <project path="external/google-benchmark" name="platform/external/google-benchmark" groups="pdk" /> + <project path="external/google-breakpad" name="platform/external/google-breakpad" groups="pdk-fs" /> + <project path="external/google-fonts/carrois-gothic-sc" name="platform/external/google-fonts/carrois-gothic-sc" groups="pdk" /> + <project path="external/google-fonts/coming-soon" name="platform/external/google-fonts/coming-soon" groups="pdk" /> + <project path="external/google-fonts/cutive-mono" name="platform/external/google-fonts/cutive-mono" groups="pdk" /> + <project path="external/google-fonts/dancing-script" name="platform/external/google-fonts/dancing-script" groups="pdk" /> + <project path="external/google-styleguide" name="platform/external/google-styleguide" groups="pdk" /> + <project path="external/google-tv-pairing-protocol" name="platform/external/google-tv-pairing-protocol" groups="pdk" /> + <project path="external/googletest" name="platform/external/googletest" groups="pdk" /> + <project path="external/gptfdisk" name="platform/external/gptfdisk" groups="pdk" /> + <project path="external/guava" name="platform/external/guava" groups="pdk" /> + <project path="external/guice" name="platform/external/guice" groups="pdk" /> + <project path="external/hamcrest" name="platform/external/hamcrest" groups="pdk" /> + <project path="external/harfbuzz_ng" name="platform/external/harfbuzz_ng" groups="pdk,qcom_msm8x26" /> + <project path="external/hyphenation-patterns" name="platform/external/hyphenation-patterns" groups="pdk" /> + <project path="external/icu" name="platform/external/icu" groups="pdk" /> + <project path="external/ImageMagick" name="platform/external/ImageMagick" groups="pdk" /> + <project path="external/ims" name="platform/external/ims" groups="pdk" /> + <project path="external/iproute2" name="platform/external/iproute2" groups="pdk" /> + <project path="external/ipsec-tools" name="platform/external/ipsec-tools" groups="pdk" /> + <project path="external/iptables" name="platform/external/iptables" groups="pdk" /> + <project path="external/iputils" name="platform/external/iputils" groups="pdk" /> + <project path="external/iw" name="platform/external/iw" groups="pdk" /> + <project path="external/jacoco" name="platform/external/jacoco" groups="pdk" /> + <project path="external/jarjar" name="platform/external/jarjar" groups="pdk" /> + <project path="external/javaparser" name="platform/external/javaparser" groups="pdk" /> + <project path="external/javasqlite" name="platform/external/javasqlite" groups="pdk" /> + <project path="external/javassist" name="platform/external/javassist" groups="pdk" /> + <project path="external/jcommander" name="platform/external/jcommander" groups="pdk" /> + <project path="external/jdiff" name="platform/external/jdiff" groups="pdk" /> + <project path="external/jemalloc" name="platform/external/jemalloc" groups="pdk" /> + <project path="external/jline" name="platform/external/jline" groups="pdk,tradefed,pdk-fs" /> + <project path="external/jmdns" name="platform/external/jmdns" groups="pdk" /> + <project path="external/jsilver" name="platform/external/jsilver" groups="pdk" /> + <project path="external/jsmn" name="platform/external/jsmn" groups="pdk" /> + <project path="external/jsoncpp" name="platform/external/jsoncpp" groups="pdk" /> + <project path="external/jsr305" name="platform/external/jsr305" groups="pdk" /> + <project path="external/jsr330" name="platform/external/jsr330" groups="pdk" /> + <project path="external/junit" name="platform/external/junit" groups="pdk" /> + <project path="external/junit-params" name="platform/external/junit-params" groups="pdk" /> + <project path="external/kernel-headers" name="platform/external/kernel-headers" groups="pdk" /> + <project path="external/kmod" name="platform/external/kmod" groups="pdk" /> + <project path="external/kotlinc" name="platform/external/kotlinc" groups="pdk" /> + <project path="external/ksoap2" name="platform/external/ksoap2" groups="pdk" /> + <project path="external/libavc" name="platform/external/libavc" groups="pdk" /> + <project path="external/libbackup" name="platform/external/libbackup" groups="pdk" /> + <project path="external/libbrillo" name="platform/external/libbrillo" groups="pdk" /> + <project path="external/libcap" name="platform/external/libcap" groups="pdk" /> + <project path="external/libcap-ng" name="platform/external/libcap-ng" groups="pdk" /> + <project path="external/libchrome" name="platform/external/libchrome" groups="pdk" /> + <project path="external/libconstrainedcrypto" name="platform/external/libconstrainedcrypto" groups="pdk" /> + <project path="external/libcups" name="platform/external/libcups" groups="pdk-cw-fs,pdk-fs" /> + <project path="external/libcxx" name="platform/external/libcxx" groups="pdk" /> + <project path="external/libcxxabi" name="platform/external/libcxxabi" groups="pdk" /> + <project path="external/libdaemon" name="platform/external/libdaemon" groups="pdk" /> + <project path="external/libdivsufsort" name="platform/external/libdivsufsort" groups="pdk" /> + <project path="external/libdrm" name="platform/external/libdrm" groups="pdk" /> + <project path="external/libedit" name="platform/external/libedit" groups="pdk" /> + <project path="external/libese" name="platform/external/libese" groups="pdk" /> + <project path="external/libevent" name="platform/external/libevent" groups="pdk" /> + <project path="external/libexif" name="platform/external/libexif" groups="pdk" /> + <project path="external/libgsm" name="platform/external/libgsm" groups="pdk" /> + <project path="external/libhevc" name="platform/external/libhevc" groups="pdk" /> + <project path="external/libjpeg-turbo" name="platform/external/libjpeg-turbo" groups="pdk" /> + <project path="external/libldac" name="platform/external/libldac" groups="pdk" /> + <project path="external/libmicrohttpd" name="platform/external/libmicrohttpd" groups="pdk" /> + <project path="external/libmpeg2" name="platform/external/libmpeg2" groups="pdk" /> + <project path="external/libmtp" name="platform/external/libmtp" groups="pdk" /> + <project path="external/libnetfilter_conntrack" name="platform/external/libnetfilter_conntrack" groups="pdk" /> + <project path="external/libnfnetlink" name="platform/external/libnfnetlink" groups="pdk" /> + <project path="external/libnl" name="platform/external/libnl" groups="pdk" /> + <project path="external/libogg" name="platform/external/libogg" groups="pdk" /> + <project path="external/libopus" name="platform/external/libopus" groups="pdk" /> + <project path="external/libpcap" name="platform/external/libpcap" groups="pdk" /> + <project path="external/libphonenumber" name="platform/external/libphonenumber" groups="pdk" /> + <project path="external/libpng" name="platform/external/libpng" groups="pdk" /> + <project path="external/libtextclassifier" name="platform/external/libtextclassifier" groups="pdk" /> + <project path="external/libunwind" name="platform/external/libunwind" groups="pdk" /> + <project path="external/libunwind_llvm" name="platform/external/libunwind_llvm" groups="pdk" /> + <project path="external/libusb" name="platform/external/libusb" groups="pdk" /> + <project path="external/libusb-compat" name="platform/external/libusb-compat" groups="pdk" /> + <project path="external/libvncserver" name="platform/external/libvncserver" groups="pdk" /> + <project path="external/libvorbis" name="platform/external/libvorbis" groups="pdk" /> + <project path="external/libvpx" name="platform/external/libvpx" groups="pdk" /> + <project path="external/libvterm" name="platform/external/libvterm" groups="pdk" /> + <project path="external/libxcam" name="platform/external/libxcam" groups="pdk" /> + <project path="external/libxml2" name="platform/external/libxml2" groups="pdk,libxml2" /> + <project path="external/libyuv" name="platform/external/libyuv" groups="pdk,libyuv" /> + <project path="external/linux-kselftest" name="platform/external/linux-kselftest" groups="vts,pdk" /> + <project path="external/lisa" name="platform/external/lisa" groups="pdk" /> + <project path="external/llvm" name="platform/external/llvm" groups="pdk" /> + <project path="external/lmfit" name="platform/external/lmfit" groups="pdk" /> + <project path="external/ltp" name="platform/external/ltp" groups="vts,pdk" /> + <project path="external/lz4" name="platform/external/lz4" groups="pdk" /> + <project path="external/lzma" name="platform/external/lzma" groups="pdk" /> + <project path="external/markdown" name="platform/external/markdown" groups="pdk" /> + <project path="external/mdnsresponder" name="platform/external/mdnsresponder" groups="pdk" /> + <project path="external/mesa3d" name="platform/external/mesa3d" groups="pdk-cw-fs,pdk-fs" /> + <project path="external/Microsoft-GSL" name="platform/external/Microsoft-GSL" groups="pdk" /> + <project path="external/minijail" name="platform/external/minijail" groups="pdk" /> + <project path="external/mksh" name="platform/external/mksh" groups="pdk" /> + <project path="external/mmc-utils" name="platform/external/mmc-utils" groups="pdk" /> + <project path="external/mockftpserver" name="platform/external/mockftpserver" groups="pdk" /> + <project path="external/mockito" name="platform/external/mockito" groups="pdk" /> + <project path="external/mockwebserver" name="platform/external/mockwebserver" groups="pdk" /> + <project path="external/modp_b64" name="platform/external/modp_b64" groups="pdk" /> + <project path="external/mp4parser" name="platform/external/mp4parser" groups="pdk" /> + <project path="external/mtpd" name="platform/external/mtpd" groups="pdk" /> + <project path="external/nanohttpd" name="platform/external/nanohttpd" groups="pdk" /> + <project path="external/nanopb-c" name="platform/external/nanopb-c" groups="pdk" /> + <project path="external/naver-fonts" name="platform/external/naver-fonts" groups="pdk" /> + <project path="external/neven" name="platform/external/neven" groups="pdk" /> + <project path="external/nfacct" name="platform/external/nfacct" groups="pdk" /> + <project path="external/nist-pkits" name="platform/external/nist-pkits" groups="pdk" /> + <project path="external/nist-sip" name="platform/external/nist-sip" groups="pdk" /> + <project path="external/noto-fonts" name="platform/external/noto-fonts" groups="pdk" /> + <project path="external/oauth" name="platform/external/oauth" groups="pdk" /> + <project path="external/objenesis" name="platform/external/objenesis" groups="pdk" /> + <project path="external/oj-libjdwp" name="platform/external/oj-libjdwp" groups="pdk" /> + <project path="external/okhttp" name="platform/external/okhttp" groups="pdk" /> + <project path="external/one-true-awk" name="platform/external/one-true-awk" groups="pdk" /> + <project path="external/opencv" name="platform/external/opencv" groups="pdk-cw-fs,pdk-fs" /> + <project path="external/owasp/sanitizer" name="platform/external/owasp/sanitizer" groups="pdk" /> + <project path="external/parameter-framework" name="platform/external/parameter-framework" groups="pdk" /> + <project path="external/pcre" name="platform/external/pcre" groups="pdk" /> + <project path="external/pdfium" name="platform/external/pdfium" groups="pdk" /> + <project path="external/perf_data_converter" name="platform/external/perf_data_converter" groups="pdk" /> + <project path="external/perfetto" name="platform/external/perfetto" groups="pdk" /> + <project path="external/piex" name="platform/external/piex" groups="pdk" /> + <project path="external/ply" name="platform/external/ply" groups="pdk" /> + <project path="external/ppp" name="platform/external/ppp" groups="pdk" /> + <project path="external/proguard" name="platform/external/proguard" groups="pdk" /> + <project path="external/protobuf" name="platform/external/protobuf" groups="pdk" /> + <project path="external/puffin" name="platform/external/puffin" groups="pdk" /> + <project path="external/python/appdirs" name="platform/external/python/appdirs" groups="vts,pdk" /> + <project path="external/python/cachetools" name="platform/external/python/cachetools" groups="vts,pdk" /> + <project path="external/python/cpython2" name="platform/external/python/cpython2" groups="pdk" /> + <project path="external/python/cpython3" name="platform/external/python/cpython3" groups="pdk" /> + <project path="external/python/dateutil" name="platform/external/python/dateutil" groups="pdk" /> + <project path="external/python/dill" name="platform/external/python/dill" groups="vts,pdk" /> + <project path="external/python/enum" name="platform/external/python/enum" groups="vts,pdk" /> + <project path="external/python/enum34" name="platform/external/python/enum34" groups="vts,pdk" /> + <project path="external/python/future" name="platform/external/python/future" groups="vts,pdk" /> + <project path="external/python/futures" name="platform/external/python/futures" groups="vts,pdk" /> + <project path="external/python/gapic-google-cloud-pubsub-v1" name="platform/external/python/gapic-google-cloud-pubsub-v1" groups="vts,pdk" /> + <project path="external/python/google-api-python-client" name="platform/external/python/google-api-python-client" groups="vts,pdk" /> + <project path="external/python/google-auth" name="platform/external/python/google-auth" groups="vts,pdk" /> + <project path="external/python/google-auth-httplib2" name="platform/external/python/google-auth-httplib2" groups="vts,pdk" /> + <project path="external/python/google-cloud-core" name="platform/external/python/google-cloud-core" groups="vts,pdk" /> + <project path="external/python/google-cloud-pubsub" name="platform/external/python/google-cloud-pubsub" groups="vts,pdk" /> + <project path="external/python/google-gax" name="platform/external/python/google-gax" groups="vts,pdk" /> + <project path="external/python/googleapis" name="platform/external/python/googleapis" groups="vts,pdk" /> + <project path="external/python/grpc-google-iam-v1" name="platform/external/python/grpc-google-iam-v1" groups="vts,pdk" /> + <project path="external/python/grpcio" name="platform/external/python/grpcio" groups="vts,pdk" /> + <project path="external/python/httplib2" name="platform/external/python/httplib2" groups="vts,pdk" /> + <project path="external/python/matplotlib" name="platform/external/python/matplotlib" groups="vts,pdk" /> + <project path="external/python/numpy" name="platform/external/python/numpy" groups="vts,pdk" /> + <project path="external/python/oauth2client" name="platform/external/python/oauth2client" groups="vts,pdk" /> + <project path="external/python/olefile" name="platform/external/python/olefile" groups="vts,pdk" /> + <project path="external/python/packaging" name="platform/external/python/packaging" groups="vts,pdk" /> + <project path="external/python/parse" name="platform/external/python/parse" groups="vts,pdk" /> + <project path="external/python/Pillow" name="platform/external/python/Pillow" groups="vts,pdk" /> + <project path="external/python/ply" name="platform/external/python/ply" groups="vts,pdk" /> + <project path="external/python/proto-google-cloud-pubsub-v1" name="platform/external/python/proto-google-cloud-pubsub-v1" groups="vts,pdk" /> + <project path="external/python/protobuf" name="platform/external/python/protobuf" groups="vts,pdk" /> + <project path="external/python/pyasn1" name="platform/external/python/pyasn1" groups="vts,pdk" /> + <project path="external/python/pyasn1-modules" name="platform/external/python/pyasn1-modules" groups="vts,pdk" /> + <project path="external/python/pyparsing" name="platform/external/python/pyparsing" groups="vts,pdk" /> + <project path="external/python/requests" name="platform/external/python/requests" groups="vts,pdk" /> + <project path="external/python/rsa" name="platform/external/python/rsa" groups="vts,pdk" /> + <project path="external/python/scipy" name="platform/external/python/scipy" groups="vts,pdk" /> + <project path="external/python/setuptools" name="platform/external/python/setuptools" groups="vts,pdk" /> + <project path="external/python/six" name="platform/external/python/six" groups="vts,pdk" /> + <project path="external/python/uritemplates" name="platform/external/python/uritemplates" groups="vts,pdk" /> + <project path="external/replicaisland" name="platform/external/replicaisland" groups="pdk" /> + <project path="external/rmi4utils" name="platform/external/rmi4utils" groups="pdk" /> + <project path="external/robolectric" name="platform/external/robolectric" groups="pdk-cw-fs,pdk-fs" /> + <project path="external/roboto-fonts" name="platform/external/roboto-fonts" groups="pdk" /> + <project path="external/rootdev" name="platform/external/rootdev" groups="pdk" /> + <project path="external/safe-iop" name="platform/external/safe-iop" groups="pdk" /> + <project path="external/scapy" name="platform/external/scapy" groups="pdk-fs" /> + <project path="external/scrypt" name="platform/external/scrypt" groups="pdk" /> + <project path="external/seccomp-tests" name="platform/external/seccomp-tests" groups="pdk" /> + <project path="external/selinux" name="platform/external/selinux" groups="pdk" /> + <project path="external/sfntly" name="platform/external/sfntly" groups="pdk,qcom_msm8x26" /> + <project path="external/shaderc/spirv-headers" name="platform/external/shaderc/spirv-headers" groups="pdk" /> + <project path="external/shflags" name="platform/external/shflags" groups="pdk" /> + <project path="external/skia" name="platform/external/skia" groups="pdk,qcom_msm8x26" /> + <project path="external/sl4a" name="platform/external/sl4a" groups="pdk" /> + <project path="external/slf4j" name="platform/external/slf4j" groups="pdk" /> + <project path="external/smali" name="platform/external/smali" groups="pdk" /> + <project path="external/snakeyaml" name="platform/external/snakeyaml" groups="pdk" /> + <project path="external/sonic" name="platform/external/sonic" groups="pdk" /> + <project path="external/sonivox" name="platform/external/sonivox" groups="pdk" /> + <project path="external/speex" name="platform/external/speex" groups="pdk" /> + <project path="external/spirv-llvm" name="platform/external/spirv-llvm" groups="pdk" /> + <project path="external/sqlite" name="platform/external/sqlite" groups="pdk" /> + <project path="external/squashfs-tools" name="platform/external/squashfs-tools" groups="pdk" /> + <project path="external/strace" name="platform/external/strace" groups="pdk" /> + <project path="external/stressapptest" name="platform/external/stressapptest" groups="pdk" /> + <project path="external/subsampling-scale-image-view" name="platform/external/subsampling-scale-image-view" clone-depth="1" /> + <project path="external/swiftshader" name="platform/external/swiftshader" groups="pdk" /> + <project path="external/syslinux" name="platform/external/syslinux" groups="pdk" /> + <project path="external/tagsoup" name="platform/external/tagsoup" groups="pdk" /> + <project path="external/tcpdump" name="platform/external/tcpdump" groups="pdk" /> + <project path="external/tensorflow" name="platform/external/tensorflow" groups="pdk" /> + <project path="external/testng" name="platform/external/testng" groups="pdk" /> + <project path="external/tinyalsa" name="platform/external/tinyalsa" groups="pdk" /> + <project path="external/tinycompress" name="platform/external/tinycompress" groups="pdk" /> + <project path="external/tinyxml" name="platform/external/tinyxml" groups="pdk" /> + <project path="external/tinyxml2" name="platform/external/tinyxml2" groups="pdk" /> + <project path="external/toolchain-utils" name="platform/external/toolchain-utils" /> + <project path="external/toybox" name="platform/external/toybox" groups="pdk" /> + <project path="external/tpm2" name="platform/external/tpm2" groups="pdk" /> + <project path="external/trappy" name="platform/external/trappy" groups="pdk" /> + <project path="external/tremolo" name="platform/external/tremolo" groups="pdk" /> + <project path="external/turbine" name="platform/external/turbine" groups="pdk" /> + <project path="external/unicode" name="platform/external/unicode" groups="pdk" /> + <project path="external/universal-tween-engine" name="platform/external/universal-tween-engine" /> + <project path="external/v4l2_codec2" name="platform/external/v4l2_codec2" groups="pdk" /> + <project path="external/v8" name="platform/external/v8" groups="pdk" /> + <project path="external/valgrind" name="platform/external/valgrind" groups="pdk" /> + <project path="external/vboot_reference" name="platform/external/vboot_reference" groups="vboot,pdk-fs" /> + <project path="external/vixl" name="platform/external/vixl" groups="pdk" /> + <project path="external/vogar" name="platform/external/vogar" groups="pdk" /> + <project path="external/volley" name="platform/external/volley" groups="pdk" /> + <project path="external/vulkan-validation-layers" name="platform/external/vulkan-validation-layers" groups="pdk" /> + <project path="external/walt" name="platform/external/walt" groups="pdk" /> + <project path="external/webp" name="platform/external/webp" groups="pdk,qcom_msm8x26" /> + <project path="external/webrtc" name="platform/external/webrtc" groups="pdk" /> + <project path="external/webview_support_interfaces" name="platform/external/webview_support_interfaces" groups="pdk" /> + <project path="external/wpa_supplicant_8" name="platform/external/wpa_supplicant_8" groups="pdk" /> + <project path="external/wycheproof" name="platform/external/wycheproof" groups="pdk" /> + <project path="external/x264" name="platform/external/x264" groups="pdk" /> + <project path="external/xmlrpcpp" name="platform/external/xmlrpcpp" groups="pdk" /> + <project path="external/xmp_toolkit" name="platform/external/xmp_toolkit" groups="pdk" /> + <project path="external/xz-embedded" name="platform/external/xz-embedded" groups="pdk" /> + <project path="external/zlib" name="platform/external/zlib" groups="pdk" /> + <project path="external/zopfli" name="platform/external/zopfli" groups="pdk" /> + <project path="external/zxing" name="platform/external/zxing" groups="pdk" /> + <project path="frameworks/av" name="platform/frameworks/av" groups="pdk" /> + <project path="frameworks/base" name="platform/frameworks/base" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/compile/libbcc" name="platform/frameworks/compile/libbcc" groups="pdk" /> + <project path="frameworks/compile/mclinker" name="platform/frameworks/compile/mclinker" groups="pdk" /> + <project path="frameworks/compile/slang" name="platform/frameworks/compile/slang" groups="pdk" /> + <project path="frameworks/data-binding" name="platform/frameworks/data-binding" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/ex" name="platform/frameworks/ex" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/hardware/interfaces" name="platform/frameworks/hardware/interfaces" groups="pdk" /> + <project path="frameworks/layoutlib" name="platform/frameworks/layoutlib" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/minikin" name="platform/frameworks/minikin" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/ml" name="platform/frameworks/ml" groups="pdk" /> + <project path="frameworks/multidex" name="platform/frameworks/multidex" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/native" name="platform/frameworks/native" groups="pdk" /> + <project path="frameworks/opt/bitmap" name="platform/frameworks/opt/bitmap" groups="pdk-fs" /> + <project path="frameworks/opt/calendar" name="platform/frameworks/opt/calendar" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/car/services" name="platform/frameworks/opt/car/services" groups="pdk-fs" /> + <project path="frameworks/opt/chips" name="platform/frameworks/opt/chips" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/colorpicker" name="platform/frameworks/opt/colorpicker" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/datetimepicker" name="platform/frameworks/opt/datetimepicker" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/inputmethodcommon" name="platform/frameworks/opt/inputmethodcommon" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/net/ethernet" name="platform/frameworks/opt/net/ethernet" groups="pdk-fs" /> + <project path="frameworks/opt/net/ims" name="platform/frameworks/opt/net/ims" groups="frameworks_ims,pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/net/lowpan" name="platform/frameworks/opt/net/lowpan" groups="pdk-fs" /> + <project path="frameworks/opt/net/voip" name="platform/frameworks/opt/net/voip" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/net/wifi" name="platform/frameworks/opt/net/wifi" groups="pdk" /> + <project path="frameworks/opt/photoviewer" name="platform/frameworks/opt/photoviewer" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/setupwizard" name="platform/frameworks/opt/setupwizard" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/telephony" name="platform/frameworks/opt/telephony" groups="pdk" /> + <project path="frameworks/opt/timezonepicker" name="platform/frameworks/opt/timezonepicker" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/opt/vcard" name="platform/frameworks/opt/vcard" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/rs" name="platform/frameworks/rs" groups="pdk" /> + <project path="frameworks/support" name="platform/frameworks/support" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/webview" name="platform/frameworks/webview" groups="pdk-cw-fs,pdk-fs" /> + <project path="frameworks/wilhelm" name="platform/frameworks/wilhelm" groups="pdk-cw-fs,pdk-fs" /> + <project path="hardware/akm" name="platform/hardware/akm" groups="pdk" /> + <project path="hardware/broadcom/libbt" name="platform/hardware/broadcom/libbt" groups="pdk" /> + <project path="hardware/broadcom/wlan" name="platform/hardware/broadcom/wlan" groups="pdk,broadcom_wlan" /> + <project path="hardware/google/apf" name="platform/hardware/google/apf" groups="pdk" /> + <project path="hardware/google/easel" name="platform/hardware/google/easel" groups="pdk,easel" /> + <project path="hardware/google/interfaces" name="platform/hardware/google/interfaces" groups="pdk" /> + <project path="hardware/intel/audio_media" name="platform/hardware/intel/audio_media" groups="intel,pdk" /> + <project path="hardware/intel/bootstub" name="platform/hardware/intel/bootstub" groups="intel,pdk" /> + <project path="hardware/intel/common/libmix" name="platform/hardware/intel/common/libmix" groups="intel,pdk" /> + <project path="hardware/intel/common/libstagefrighthw" name="platform/hardware/intel/common/libstagefrighthw" groups="intel,pdk" /> + <project path="hardware/intel/common/libva" name="platform/hardware/intel/common/libva" groups="intel,pdk" /> + <project path="hardware/intel/common/libwsbm" name="platform/hardware/intel/common/libwsbm" groups="intel,pdk" /> + <project path="hardware/intel/common/omx-components" name="platform/hardware/intel/common/omx-components" groups="intel,pdk" /> + <project path="hardware/intel/common/utils" name="platform/hardware/intel/common/utils" groups="intel,pdk" /> + <project path="hardware/intel/common/wrs_omxil_core" name="platform/hardware/intel/common/wrs_omxil_core" groups="intel,pdk" /> + <project path="hardware/intel/img/hwcomposer" name="platform/hardware/intel/img/hwcomposer" groups="intel,pdk" /> + <project path="hardware/intel/img/psb_headers" name="platform/hardware/intel/img/psb_headers" groups="intel,pdk" /> + <project path="hardware/intel/img/psb_video" name="platform/hardware/intel/img/psb_video" groups="intel,pdk" /> + <project path="hardware/interfaces" name="platform/hardware/interfaces" groups="pdk" /> + <project path="hardware/invensense" name="platform/hardware/invensense" groups="invensense,pdk" /> + <project path="hardware/libhardware" name="platform/hardware/libhardware" groups="pdk" /> + <project path="hardware/libhardware_legacy" name="platform/hardware/libhardware_legacy" groups="pdk" /> + <project path="hardware/marvell/bt" name="platform/hardware/marvell/bt" groups="marvell_bt,pdk" /> + <project path="hardware/nxp/nfc" name="platform/hardware/nxp/nfc" groups="pdk" /> + <project path="hardware/nxp/secure_element" name="platform/hardware/nxp/secure_element" groups="pdk" /> + <project path="hardware/qcom/audio" name="platform/hardware/qcom/audio" groups="qcom,qcom_audio,pdk" /> + <project path="hardware/qcom/bootctrl" name="platform/hardware/qcom/bootctrl" groups="pdk" /> + <project path="hardware/qcom/bt" name="platform/hardware/qcom/bt" groups="qcom,pdk" /> + <project path="hardware/qcom/camera" name="platform/hardware/qcom/camera" groups="qcom_camera,pdk" /> + <project path="hardware/qcom/data/ipacfg-mgr" name="platform/hardware/qcom/data/ipacfg-mgr" groups="qcom,pdk" /> + <project path="hardware/qcom/display" name="platform/hardware/qcom/display" groups="pdk,qcom,qcom_display" /> + <project path="hardware/qcom/gps" name="platform/hardware/qcom/gps" groups="qcom,qcom_gps,pdk" /> + <project path="hardware/qcom/keymaster" name="platform/hardware/qcom/keymaster" groups="qcom,qcom_keymaster,pdk" /> + <project path="hardware/qcom/media" name="platform/hardware/qcom/media" groups="qcom,pdk" /> + <project path="hardware/qcom/msm8960" name="platform/hardware/qcom/msm8960" groups="qcom_msm8960,pdk" /> + <project path="hardware/qcom/msm8994" name="platform/hardware/qcom/msm8994" groups="qcom_msm8994,pdk" /> + <project path="hardware/qcom/msm8996" name="platform/hardware/qcom/msm8996" groups="qcom_msm8996,pdk" /> + <project path="hardware/qcom/msm8998" name="platform/hardware/qcom/msm8998" groups="qcom_msm8998,pdk" /> + <project path="hardware/qcom/msm8x09" name="platform/hardware/qcom/msm8x09" groups="qcom_msm8x09" /> + <project path="hardware/qcom/msm8x26" name="platform/hardware/qcom/msm8x26" groups="qcom_msm8x26,pdk" /> + <project path="hardware/qcom/msm8x27" name="platform/hardware/qcom/msm8x27" groups="qcom_msm8x27,pdk" /> + <project path="hardware/qcom/msm8x84" name="platform/hardware/qcom/msm8x84" groups="qcom_msm8x84,pdk" /> + <project path="hardware/qcom/neuralnetworks/hvxservice" name="platform/hardware/qcom/neuralnetworks/hvxservice" groups="wahoo" /> + <project path="hardware/qcom/power" name="platform/hardware/qcom/power" groups="qcom,pdk" /> + <project path="hardware/qcom/wlan" name="platform/hardware/qcom/wlan" groups="qcom_wlan,pdk" /> + <project path="hardware/ril" name="platform/hardware/ril" groups="pdk" /> + <project path="hardware/st/nfc" name="platform/hardware/st/nfc" groups="pdk" /> + <project path="kernel/configs" name="kernel/configs" groups="vts,pdk" /> + <project path="kernel/tests" name="kernel/tests" /> + <project path="libcore" name="platform/libcore" groups="pdk" /> + <project path="libnativehelper" name="platform/libnativehelper" groups="pdk" /> + <project path="packages/apps/BasicSmsReceiver" name="platform/packages/apps/BasicSmsReceiver" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/Bluetooth" name="platform/packages/apps/Bluetooth" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/Browser2" name="platform/packages/apps/Browser2" groups="pdk-fs" /> + <project path="packages/apps/Calendar" name="platform/packages/apps/Calendar" groups="pdk-fs" /> + <project path="packages/apps/Camera2" name="platform/packages/apps/Camera2" groups="pdk-fs" /> + <project path="packages/apps/Car/Dialer" name="platform/packages/apps/Car/Dialer" groups="pdk-fs" /> + <project path="packages/apps/Car/Hvac" name="platform/packages/apps/Car/Hvac" groups="pdk-fs" /> + <project path="packages/apps/Car/LatinIME" name="platform/packages/apps/Car/LatinIME" groups="pdk-fs" /> + <project path="packages/apps/Car/Launcher" name="platform/packages/apps/Car/Launcher" groups="pdk-fs" /> + <project path="packages/apps/Car/LensPicker" name="platform/packages/apps/Car/LensPicker" groups="pdk-fs" /> + <project path="packages/apps/Car/libs" name="platform/packages/apps/Car/libs" groups="pdk-fs" /> + <project path="packages/apps/Car/LocalMediaPlayer" name="platform/packages/apps/Car/LocalMediaPlayer" groups="pdk-fs" /> + <project path="packages/apps/Car/Media" name="platform/packages/apps/Car/Media" groups="pdk-fs" /> + <project path="packages/apps/Car/Messenger" name="platform/packages/apps/Car/Messenger" groups="pdk-fs" /> + <project path="packages/apps/Car/Overview" name="platform/packages/apps/Car/Overview" groups="pdk-fs" /> + <project path="packages/apps/Car/Radio" name="platform/packages/apps/Car/Radio" groups="pdk-fs" /> + <project path="packages/apps/Car/Settings" name="platform/packages/apps/Car/Settings" groups="pdk-fs" /> + <project path="packages/apps/Car/Stream" name="platform/packages/apps/Car/Stream" groups="pdk-fs" /> + <project path="packages/apps/Car/SystemUpdater" name="platform/packages/apps/Car/SystemUpdater" groups="pdk-fs" /> + <project path="packages/apps/CarrierConfig" name="platform/packages/apps/CarrierConfig" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/CellBroadcastReceiver" name="platform/packages/apps/CellBroadcastReceiver" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/CertInstaller" name="platform/packages/apps/CertInstaller" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/Contacts" name="platform/packages/apps/Contacts" groups="pdk-fs" /> + <project path="packages/apps/DeskClock" name="platform/packages/apps/DeskClock" groups="pdk-fs" /> + <project path="packages/apps/DevCamera" name="platform/packages/apps/DevCamera" groups="pdk" /> + <project path="packages/apps/Dialer" name="platform/packages/apps/Dialer" groups="pdk-fs" /> + <project path="packages/apps/DocumentsUI" name="platform/packages/apps/DocumentsUI" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/Email" name="platform/packages/apps/Email" groups="pdk-fs" /> + <project path="packages/apps/EmergencyInfo" name="platform/packages/apps/EmergencyInfo" groups="pdk-fs" /> + <project path="packages/apps/ExactCalculator" name="platform/packages/apps/ExactCalculator" groups="pdk-fs" /> + <project path="packages/apps/Gallery" name="platform/packages/apps/Gallery" groups="pdk-fs" /> + <project path="packages/apps/Gallery2" name="platform/packages/apps/Gallery2" groups="pdk-fs" /> + <project path="packages/apps/HTMLViewer" name="platform/packages/apps/HTMLViewer" groups="pdk-fs" /> + <project path="packages/apps/KeyChain" name="platform/packages/apps/KeyChain" groups="pdk-fs" /> + <project path="packages/apps/Launcher2" name="platform/packages/apps/Launcher2" groups="pdk-fs" /> + <project path="packages/apps/Launcher3" name="platform/packages/apps/Launcher3" groups="pdk-fs" /> + <project path="packages/apps/LegacyCamera" name="platform/packages/apps/LegacyCamera" groups="pdk-fs" /> + <project path="packages/apps/ManagedProvisioning" name="platform/packages/apps/ManagedProvisioning" groups="pdk-fs" /> + <project path="packages/apps/Messaging" name="platform/packages/apps/Messaging" groups="pdk-fs" /> + <project path="packages/apps/Music" name="platform/packages/apps/Music" groups="pdk-fs" /> + <project path="packages/apps/MusicFX" name="platform/packages/apps/MusicFX" groups="pdk-fs" /> + <project path="packages/apps/Nfc" name="platform/packages/apps/Nfc" groups="apps_nfc,pdk-fs" /> + <project path="packages/apps/OneTimeInitializer" name="platform/packages/apps/OneTimeInitializer" groups="pdk-fs" /> + <project path="packages/apps/PackageInstaller" name="platform/packages/apps/PackageInstaller" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/PhoneCommon" name="platform/packages/apps/PhoneCommon" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/apps/Protips" name="platform/packages/apps/Protips" groups="pdk-fs" /> + <project path="packages/apps/Provision" name="platform/packages/apps/Provision" groups="pdk-fs" /> + <project path="packages/apps/QuickSearchBox" name="platform/packages/apps/QuickSearchBox" groups="pdk-fs" /> + <project path="packages/apps/SafetyRegulatoryInfo" name="platform/packages/apps/SafetyRegulatoryInfo" groups="pdk-fs" /> + <project path="packages/apps/SecureElement" name="platform/packages/apps/SecureElement" groups="apps_se,pdk-fs" /> + <project path="packages/apps/Settings" name="platform/packages/apps/Settings" groups="pdk-fs" /> + <project path="packages/apps/SoundRecorder" name="platform/packages/apps/SoundRecorder" groups="pdk-fs" /> + <project path="packages/apps/SpareParts" name="platform/packages/apps/SpareParts" groups="pdk-fs" /> + <project path="packages/apps/Stk" name="platform/packages/apps/Stk" groups="apps_stk,pdk-fs" /> + <project path="packages/apps/StorageManager" name="platform/packages/apps/StorageManager" groups="pdk-fs" /> + <project path="packages/apps/Tag" name="platform/packages/apps/Tag" groups="pdk-fs" /> + <project path="packages/apps/Terminal" name="platform/packages/apps/Terminal" groups="pdk-fs" /> + <project path="packages/apps/Test/connectivity" name="platform/packages/apps/Test/connectivity" groups="pdk" /> + <project path="packages/apps/TimeZoneData" name="platform/packages/apps/TimeZoneData" groups="pdk" /> + <project path="packages/apps/TimeZoneUpdater" name="platform/packages/apps/TimeZoneUpdater" groups="pdk" /> + <project path="packages/apps/Traceur" name="platform/packages/apps/Traceur" groups="pdk-fs" /> + <project path="packages/apps/TvSettings" name="platform/packages/apps/TvSettings" groups="pdk-fs" /> + <project path="packages/apps/TV" name="platform/packages/apps/TV" /> + <project path="packages/apps/UnifiedEmail" name="platform/packages/apps/UnifiedEmail" groups="pdk-fs" /> + <project path="packages/apps/WallpaperPicker" name="platform/packages/apps/WallpaperPicker" groups="pdk-fs" /> + <project path="packages/experimental" name="platform/packages/experimental" /> + <project path="packages/inputmethods/LatinIME" name="platform/packages/inputmethods/LatinIME" groups="pdk-fs" /> + <project path="packages/inputmethods/OpenWnn" name="platform/packages/inputmethods/OpenWnn" groups="pdk-fs" /> + <project path="packages/providers/ApplicationsProvider" name="platform/packages/providers/ApplicationsProvider" groups="pdk-fs" /> + <project path="packages/providers/BlockedNumberProvider" name="platform/packages/providers/BlockedNumberProvider" groups="pdk-fs" /> + <project path="packages/providers/BookmarkProvider" name="platform/packages/providers/BookmarkProvider" groups="pdk-fs" /> + <project path="packages/providers/CalendarProvider" name="platform/packages/providers/CalendarProvider" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/providers/CallLogProvider" name="platform/packages/providers/CallLogProvider" groups="pdk-fs" /> + <project path="packages/providers/ContactsProvider" name="platform/packages/providers/ContactsProvider" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/providers/DownloadProvider" name="platform/packages/providers/DownloadProvider" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/providers/MediaProvider" name="platform/packages/providers/MediaProvider" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/providers/PartnerBookmarksProvider" name="platform/packages/providers/PartnerBookmarksProvider" groups="pdk-fs" /> + <project path="packages/providers/TelephonyProvider" name="platform/packages/providers/TelephonyProvider" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/providers/TvProvider" name="platform/packages/providers/TvProvider" groups="pdk-fs" /> + <project path="packages/providers/UserDictionaryProvider" name="platform/packages/providers/UserDictionaryProvider" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/screensavers/Basic" name="platform/packages/screensavers/Basic" groups="pdk-fs" /> + <project path="packages/screensavers/PhotoTable" name="platform/packages/screensavers/PhotoTable" groups="pdk-fs" /> + <project path="packages/screensavers/WebView" name="platform/packages/screensavers/WebView" groups="pdk-fs" /> + <project path="packages/services/BuiltInPrintService" name="platform/packages/services/BuiltInPrintService" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/services/Car" name="platform/packages/services/Car" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/services/Mms" name="platform/packages/services/Mms" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/services/NetworkRecommendation" name="platform/packages/services/NetworkRecommendation" groups="pdk-fs" /> + <project path="packages/services/Telecomm" name="platform/packages/services/Telecomm" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/services/Telephony" name="platform/packages/services/Telephony" groups="pdk-cw-fs,pdk-fs" /> + <project path="packages/wallpapers/LivePicker" name="platform/packages/wallpapers/LivePicker" groups="pdk-fs" /> + <project path="pdk" name="platform/pdk" groups="pdk" /> + <project path="platform_testing" name="platform/platform_testing" groups="pdk-fs,pdk-cw-fs,cts" /> + <project path="prebuilts/abi-dumps/ndk" name="platform/prebuilts/abi-dumps/ndk" groups="pdk-fs" clone-depth="1" /> + <project path="prebuilts/abi-dumps/vndk" name="platform/prebuilts/abi-dumps/vndk" groups="pdk-fs" clone-depth="1" /> + <project path="prebuilts/android-emulator" name="platform/prebuilts/android-emulator" groups="pdk-fs" clone-depth="1" /> + <project path="prebuilts/build-tools" name="platform/prebuilts/build-tools" groups="pdk" clone-depth="1" /> + <project path="prebuilts/checkstyle" name="platform/prebuilts/checkstyle" groups="pdk" clone-depth="1" /> + <project path="prebuilts/clang-tools" name="platform/prebuilts/clang-tools" groups="pdk" clone-depth="1" /> + <project path="prebuilts/clang/host/darwin-x86" name="platform/prebuilts/clang/host/darwin-x86" groups="pdk,darwin" clone-depth="1" /> + <project path="prebuilts/clang/host/linux-x86" name="platform/prebuilts/clang/host/linux-x86" groups="pdk" clone-depth="1" /> + <project path="prebuilts/deqp" name="platform/prebuilts/deqp" groups="pdk-fs" clone-depth="1" /> + <project path="prebuilts/devtools" name="platform/prebuilts/devtools" groups="pdk-fs" clone-depth="1" /> + <project path="prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9" name="platform/prebuilts/gcc/darwin-x86/aarch64/aarch64-linux-android-4.9" groups="pdk,darwin,arm" clone-depth="1" /> + <project path="prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.9" name="platform/prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.9" groups="pdk,darwin,arm" clone-depth="1" /> + <project path="prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1" name="platform/prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1" groups="pdk,darwin" clone-depth="1" /> + <project path="prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9" name="platform/prebuilts/gcc/darwin-x86/mips/mips64el-linux-android-4.9" groups="pdk,darwin,mips" clone-depth="1" /> + <project path="prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9" name="platform/prebuilts/gcc/darwin-x86/x86/x86_64-linux-android-4.9" groups="pdk,darwin,x86" clone-depth="1" /> + <project path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9" groups="pdk,linux,arm" clone-depth="1" /> + <project path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9" groups="pdk,linux,arm" clone-depth="1" /> + <project path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8" groups="pdk,linux" clone-depth="1" /> + <project path="prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8" name="platform/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8" groups="pdk-fs" clone-depth="1" /> + <project path="prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9" name="platform/prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9" groups="pdk,linux,mips" clone-depth="1" /> + <project path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9" groups="pdk,linux,x86" clone-depth="1" /> + <project path="prebuilts/gdb/darwin-x86" name="platform/prebuilts/gdb/darwin-x86" groups="darwin" clone-depth="1" /> + <project path="prebuilts/gdb/linux-x86" name="platform/prebuilts/gdb/linux-x86" groups="linux" clone-depth="1" /> + <project path="prebuilts/go/darwin-x86" name="platform/prebuilts/go/darwin-x86" groups="darwin,pdk,tradefed" clone-depth="1" /> + <project path="prebuilts/go/linux-x86" name="platform/prebuilts/go/linux-x86" groups="linux,pdk,tradefed" clone-depth="1" /> + <project path="prebuilts/gradle-plugin" name="platform/prebuilts/gradle-plugin" groups="pdk-cw-fs,pdk-fs" clone-depth="1" /> + <project path="prebuilts/jdk/jdk8" name="platform/prebuilts/jdk/jdk8" groups="pdk" clone-depth="1" /> + <project path="prebuilts/jdk/jdk9" name="platform/prebuilts/jdk/jdk9" groups="pdk" clone-depth="1" /> + <project path="prebuilts/libs/libedit" name="platform/prebuilts/libs/libedit" groups="pdk-cw-fs,pdk-fs" clone-depth="1" /> + <project path="prebuilts/maven_repo/android" name="platform/prebuilts/maven_repo/android" groups="pdk-cw-fs,pdk-fs" clone-depth="1" /> + <project path="prebuilts/maven_repo/bumptech" name="platform/prebuilts/maven_repo/bumptech" groups="pdk-cw-fs,pdk-fs" clone-depth="1" /> + <project path="prebuilts/maven_repo/google-play-service-client-libraries-3p" name="platform/prebuilts/maven_repo/google-play-service-client-libraries-3p" clone-depth="1" /> + <project path="prebuilts/misc" name="platform/prebuilts/misc" groups="pdk" clone-depth="1" /> + <project path="prebuilts/ndk" name="platform/prebuilts/ndk" groups="pdk" clone-depth="1" /> + <project path="prebuilts/python/darwin-x86/2.7.5" name="platform/prebuilts/python/darwin-x86/2.7.5" groups="darwin,pdk,pdk-cw-fs,pdk-fs" clone-depth="1" /> + <project path="prebuilts/python/linux-x86/2.7.5" name="platform/prebuilts/python/linux-x86/2.7.5" groups="linux,pdk,pdk-cw-fs,pdk-fs" clone-depth="1" /> + <project path="prebuilts/qemu-kernel" name="platform/prebuilts/qemu-kernel" groups="pdk" clone-depth="1" /> + <project path="prebuilts/r8" name="platform/prebuilts/r8" groups="pdk" clone-depth="1" /> + <project path="prebuilts/sdk" name="platform/prebuilts/sdk" groups="pdk" clone-depth="1" /> + <project path="prebuilts/tools" name="platform/prebuilts/tools" groups="pdk,tools" clone-depth="1" /> + <project path="sdk" name="platform/sdk" groups="pdk-cw-fs,pdk-fs" /> + <project path="system/bt" name="platform/system/bt" groups="pdk" /> + <project path="system/ca-certificates" name="platform/system/ca-certificates" groups="pdk" /> + <project path="system/chre" name="platform/system/chre" groups="pdk" /> + <project path="system/connectivity/wificond" name="platform/system/connectivity/wificond" groups="pdk" /> + <project path="system/connectivity/wifilogd" name="platform/system/connectivity/wifilogd" groups="pdk" /> + <project path="system/core" name="platform/system/core" groups="pdk" /> + <project path="system/extras" name="platform/system/extras" groups="pdk" /> + <project path="system/gatekeeper" name="platform/system/gatekeeper" groups="pdk" /> + <project path="system/hardware/interfaces" name="platform/system/hardware/interfaces" groups="pdk" /> + <project path="system/hwservicemanager" name="platform/system/hwservicemanager" groups="pdk" /> + <project path="system/iot/attestation" name="platform/system/iot/attestation" groups="pdk" /> + <project path="system/keymaster" name="platform/system/keymaster" groups="pdk" /> + <project path="system/libfmq" name="platform/system/libfmq" groups="pdk" /> + <project path="system/libhidl" name="platform/system/libhidl" groups="pdk" /> + <project path="system/libhwbinder" name="platform/system/libhwbinder" groups="pdk" /> + <project path="system/libufdt" name="platform/system/libufdt" groups="pdk" /> + <project path="system/libvintf" name="platform/system/libvintf" groups="pdk" /> + <project path="system/media" name="platform/system/media" groups="pdk" /> + <project path="system/netd" name="platform/system/netd" groups="pdk" /> + <project path="system/nfc" name="platform/system/nfc" groups="pdk" /> + <project path="system/nvram" name="platform/system/nvram" groups="pdk" /> + <project path="system/security" name="platform/system/security" groups="pdk" /> + <project path="system/sepolicy" name="platform/system/sepolicy" groups="pdk" /> + <project path="system/timezone" name="platform/system/timezone" groups="pdk" /> + <project path="system/tools/aidl" name="platform/system/tools/aidl" groups="pdk-cw-fs,pdk-fs" /> + <project path="system/tools/bpt" name="platform/system/tools/bpt" groups="pdk" /> + <project path="system/tools/hidl" name="platform/system/tools/hidl" groups="pdk" /> + <project path="system/update_engine" name="platform/system/update_engine" groups="pdk" /> + <project path="system/vold" name="platform/system/vold" groups="pdk" /> + <project path="test/framework" name="platform/test/framework" groups="vts,pdk" /> + <project path="test/mlts/benchmark" name="platform/test/mlts/benchmark" groups="pdk" /> + <project path="test/mlts/models" name="platform/test/mlts/models" groups="pdk" /> + <project path="test/sts" name="platform/test/sts" groups="sts,pdk" /> + <project path="test/vti/alert" name="platform/test/vti/alert" groups="vts,pdk" /> + <project path="test/vti/dashboard" name="platform/test/vti/dashboard" groups="vts,pdk" /> + <project path="test/vti/fuzz_test_serving" name="platform/test/vti/fuzz_test_serving" groups="vts,pdk" /> + <project path="test/vti/test_serving" name="platform/test/vti/test_serving" groups="vts,pdk" /> + <project path="test/vts" name="platform/test/vts" groups="vts,pdk" /> + <project path="test/vts-testcase/fuzz" name="platform/test/vts-testcase/fuzz" groups="vts,pdk" /> + <project path="test/vts-testcase/hal" name="platform/test/vts-testcase/hal" groups="vts,pdk" /> + <project path="test/vts-testcase/hal-trace" name="platform/test/vts-testcase/hal-trace" groups="vts,pdk" /> + <project path="test/vts-testcase/kernel" name="platform/test/vts-testcase/kernel" groups="vts,pdk" /> + <project path="test/vts-testcase/nbu" name="platform/test/vts-testcase/nbu" groups="vts,pdk" /> + <project path="test/vts-testcase/performance" name="platform/test/vts-testcase/performance" groups="vts,pdk" /> + <project path="test/vts-testcase/security" name="platform/test/vts-testcase/security" groups="vts,pdk" /> + <project path="test/vts-testcase/vndk" name="platform/test/vts-testcase/vndk" groups="vts,pdk" /> + <project path="toolchain/benchmark" name="toolchain/benchmark" /> + <project path="toolchain/binutils" name="toolchain/binutils" groups="pdk" /> + <project path="toolchain/pgo-profiles" name="toolchain/pgo-profiles" groups="pdk" /> + <project path="tools/acloud" name="platform/tools/acloud" groups="tools,vts,pdk,tradefed" /> + <project path="tools/adt/idea" name="platform/tools/adt/idea" groups="notdefault,tools" /> + <project path="tools/apksig" name="platform/tools/apksig" groups="pdk,tradefed" /> + <project path="tools/apkzlib" name="platform/tools/apkzlib" groups="pdk,tradefed" /> + <project path="tools/base" name="platform/tools/base" groups="notdefault,tools" /> + <project path="tools/build" name="platform/tools/build" groups="notdefault,tools" /> + <project path="tools/dexter" name="platform/tools/dexter" groups="tools,pdk-fs" /> + <project path="tools/external/fat32lib" name="platform/tools/external/fat32lib" groups="tools" /> + <project path="tools/external/gradle" name="platform/tools/external/gradle" groups="tools" clone-depth="1" /> + <project path="tools/idea" name="platform/tools/idea" groups="notdefault,tools" /> + <project path="tools/loganalysis" name="platform/tools/loganalysis" groups="nopresubmit,pdk,tradefed" /> + <project path="tools/metalava" name="platform/tools/metalava" groups="tools" /> + <project path="tools/motodev" name="platform/tools/motodev" groups="notdefault,motodev" /> + <project path="tools/repohooks" name="platform/tools/repohooks" groups="adt-infra,cts,developers,motodev,pdk,tools,tradefed" /> + <project path="tools/security" name="platform/tools/security" groups="pdk,tools" /> + <project path="tools/studio/cloud" name="platform/tools/studio/cloud" groups="notdefault,tools" /> + <project path="tools/swt" name="platform/tools/swt" groups="notdefault,tools" /> + <project path="tools/test/connectivity" name="platform/tools/test/connectivity" groups="pdk" /> + <project path="tools/test/graphicsbenchmark" name="platform/tools/test/graphicsbenchmark" groups="pdk" /> + <project path="tools/tradefederation/core" name="platform/tools/tradefederation" groups="pdk,tradefed" /> + <project path="tools/tradefederation/contrib" name="platform/tools/tradefederation/contrib" groups="pdk,tradefed" /> + + <repo-hooks in-project="platform/tools/repohooks" enabled-list="pre-upload" /> + +</manifest> diff --git a/spec/fixtures/trace/sample_trace b/spec/fixtures/trace/sample_trace index c65cf05d5ca..7bfe3f83b7b 100644 --- a/spec/fixtures/trace/sample_trace +++ b/spec/fixtures/trace/sample_trace @@ -41,7 +41,7 @@ From https://gitlab.com/gitlab-org/gitlab-ce section_end:1522927113:get_sources [0Ksection_start:1522927113:restore_cache [0K[32;1mChecking cache for ruby-2.3.6-with-yarn...[0;m -Downloading cache.zip from http://runners-cache-5-internal.gitlab.com:444/runner/project/13083/ruby-2.3.6-with-yarn[0;m +Downloading cache.zip from http://runners-cache-5-internal.gitlab.com:444/runner/project/13083/ruby-2.3.6-with-yarn[0;m [32;1mSuccessfully extracted cache[0;m section_end:1522927128:restore_cache [0Ksection_start:1522927128:download_artifacts @@ -51,7 +51,7 @@ Downloading artifacts from coordinator... ok [0;m id[0;m=61303215 respon Downloading artifacts from coordinator... ok [0;m id[0;m=61303216 responseStatus[0;m=200 OK token[0;m=iy2yYbq8 [32;1mDownloading artifacts for setup-test-env (61303217)...[0;m Downloading artifacts from coordinator... ok [0;m id[0;m=61303217 responseStatus[0;m=200 OK token[0;m=ur1g79-4 -[0;33mWARNING: tmp/tests/gitlab-shell/.gitlab_shell_secret: chmod tmp/tests/gitlab-shell/.gitlab_shell_secret: no such file or directory (suppressing repeats)[0;m +[0;33mWARNING: tmp/tests/gitlab-shell/.gitlab_shell_secret: chmod tmp/tests/gitlab-shell/.gitlab_shell_secret: no such file or directory (suppressing repeats)[0;m section_end:1522927141:download_artifacts [0Ksection_start:1522927141:build_script [0K[32;1m$ bundle --version[0;m @@ -1486,7 +1486,7 @@ Gitlab::ImportExport::ProjectTreeSaver overrides the project description group members does not export group members if it has no permission - does not export group members as master + does not export group members as maintainer exports group members as group owner as admin exports group members as admin @@ -1690,7 +1690,7 @@ GroupsController and logged in as Developer behaves like member without ability to create subgroups renders the 404 page (PENDING: around hook at ./spec/spec_helper.rb:186 did not execute the example) - and logged in as Master + and logged in as Maintainer behaves like member without ability to create subgroups renders the 404 page (PENDING: around hook at ./spec/spec_helper.rb:186 did not execute the example) and can_create_group is false @@ -1706,7 +1706,7 @@ GroupsController and logged in as Developer behaves like member without ability to create subgroups renders the 404 page (PENDING: around hook at ./spec/spec_helper.rb:186 did not execute the example) - and logged in as Master + and logged in as Maintainer behaves like member without ability to create subgroups renders the 404 page (PENDING: around hook at ./spec/spec_helper.rb:186 did not execute the example) GET #activity @@ -2324,7 +2324,7 @@ Editing file blob shows blob editor with same branch with protected branch shows blob editor with patch branch - as master + as maintainer shows blob editor with same branch Boards::Lists::MoveService @@ -2880,7 +2880,7 @@ API::V3::Environments won't update the external_url if only the name is passed returns a 404 if the environment does not exist DELETE /projects/:id/environments/:environment_id - as a master + as a maintainer returns a 200 for an existing environment returns a 404 for non existing id a non member @@ -3001,11 +3001,11 @@ LfsFileLock #can_be_unlocked_by? when it's forced can be unlocked by the author - can be unlocked by a master + can be unlocked by a maintainer can't be unlocked by other user when it isn't forced can be unlocked by the author - can't be unlocked by a master + can't be unlocked by a maintainer can't be unlocked by other user Gitlab::Ci::Config::Entry::Boolean @@ -3069,7 +3069,7 @@ Pending: (Failures listed here are expected and do not affect your suite's statu # around hook at ./spec/spec_helper.rb:186 did not execute the example # ./spec/controllers/groups_controller_spec.rb:25 - 5) GroupsController GET #new when creating subgroups and can_create_group is true and logged in as Master behaves like member without ability to create subgroups renders the 404 page + 5) GroupsController GET #new when creating subgroups and can_create_group is true and logged in as Maintainer behaves like member without ability to create subgroups renders the 404 page # around hook at ./spec/spec_helper.rb:186 did not execute the example # ./spec/controllers/groups_controller_spec.rb:25 @@ -3089,7 +3089,7 @@ Pending: (Failures listed here are expected and do not affect your suite's statu # around hook at ./spec/spec_helper.rb:186 did not execute the example # ./spec/controllers/groups_controller_spec.rb:25 - 10) GroupsController GET #new when creating subgroups and can_create_group is false and logged in as Master behaves like member without ability to create subgroups renders the 404 page + 10) GroupsController GET #new when creating subgroups and can_create_group is false and logged in as Maintainer behaves like member without ability to create subgroups renders the 404 page # around hook at ./spec/spec_helper.rb:186 did not execute the example # ./spec/controllers/groups_controller_spec.rb:25 @@ -3237,7 +3237,7 @@ Pending: (Failures listed here are expected and do not affect your suite's statu # around hook at ./spec/spec_helper.rb:190 did not execute the example # ./spec/services/groups/transfer_service_spec.rb:212 - 47) Groups::TransferService#execute when transferring a subgroup into another group when the group is allowed to be transferred should update parent group to the new parent + 47) Groups::TransferService#execute when transferring a subgroup into another group when the group is allowed to be transferred should update parent group to the new parent # around hook at ./spec/spec_helper.rb:190 did not execute the example # ./spec/services/groups/transfer_service_spec.rb:216 @@ -3435,10 +3435,10 @@ section_end:1522927515:after_script section_end:1522927516:archive_cache [0Ksection_start:1522927516:upload_artifacts [0K[32;1mUploading artifacts...[0;m -coverage/: found 5 matching files [0;m -knapsack/: found 5 matching files [0;m -rspec_flaky/: found 4 matching files [0;m -[0;33mWARNING: tmp/capybara/: no matching files [0;m +coverage/: found 5 matching files [0;m +knapsack/: found 5 matching files [0;m +rspec_flaky/: found 4 matching files [0;m +[0;33mWARNING: tmp/capybara/: no matching files [0;m Uploading artifacts to coordinator... ok [0;m id[0;m=61303283 responseStatus[0;m=201 Created token[0;m=rusBKvxM section_end:1522927520:upload_artifacts [0K[32;1mJob succeeded diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index f76ed4bfda4..77410e0070c 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -21,27 +21,6 @@ describe IssuablesHelper do end end - describe '#group_dropdown_label' do - let(:group) { create(:group) } - let(:default) { 'default label' } - - it 'returns default group label when group_id is nil' do - expect(group_dropdown_label(nil, default)).to eq('default label') - end - - it 'returns "any group" when group_id is 0' do - expect(group_dropdown_label('0', default)).to eq('Any group') - end - - it 'returns group full path when a group was found for the provided id' do - expect(group_dropdown_label(group.id, default)).to eq(group.full_name) - end - - it 'returns default label when a group was not found for the provided id' do - expect(group_dropdown_label(9999, default)).to eq('default label') - end - end - describe '#issuable_labels_tooltip' do it 'returns label text with no labels' do expect(issuable_labels_tooltip([])).to eq("Labels") diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index d5ed5c59c61..597648b064d 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -11,7 +11,7 @@ describe MarkupHelper do before do # Ensure the generated reference links aren't redacted - project.add_master(user) + project.add_maintainer(user) # Helper expects a @project instance variable helper.instance_variable_set(:@project, project) diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb index 460d3b6a7e4..343e140f5fb 100644 --- a/spec/helpers/namespaces_helper_spec.rb +++ b/spec/helpers/namespaces_helper_spec.rb @@ -28,6 +28,16 @@ describe NamespacesHelper do expect(options).not_to include(admin_group.name) expect(options).to include(user_group.name) + expect(options).to include(user.name) + end + + it 'returns only groups if groups_only option is true' do + allow(helper).to receive(:current_user).and_return(user) + + options = helper.namespaces_options(nil, groups_only: true) + + expect(options).not_to include(user.name) + expect(options).to include(user_group.name) end context 'when nested groups are available', :nested_groups do diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index b992bdb4a5e..21461e46cf4 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -6,18 +6,18 @@ describe NotesHelper do let(:owner) { create(:owner) } let(:group) { create(:group) } let(:project) { create(:project, namespace: group) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } let(:owner_note) { create(:note, author: owner, project: project) } - let(:master_note) { create(:note, author: master, project: project) } + let(:maintainer_note) { create(:note, author: maintainer, project: project) } let(:reporter_note) { create(:note, author: reporter, project: project) } - let!(:notes) { [owner_note, master_note, reporter_note] } + let!(:notes) { [owner_note, maintainer_note, reporter_note] } before do group.add_owner(owner) - project.add_master(master) + project.add_maintainer(maintainer) project.add_reporter(reporter) project.add_guest(guest) end @@ -25,16 +25,16 @@ describe NotesHelper do describe "#notes_max_access_for_users" do it 'returns access levels' do expect(helper.note_max_access_for_user(owner_note)).to eq(Gitlab::Access::OWNER) - expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER) + expect(helper.note_max_access_for_user(maintainer_note)).to eq(Gitlab::Access::MAINTAINER) expect(helper.note_max_access_for_user(reporter_note)).to eq(Gitlab::Access::REPORTER) end it 'handles access in different projects' do second_project = create(:project) - second_project.add_reporter(master) - other_note = create(:note, author: master, project: second_project) + second_project.add_reporter(maintainer) + other_note = create(:note, author: maintainer, project: second_project) - expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER) + expect(helper.note_max_access_for_user(maintainer_note)).to eq(Gitlab::Access::MAINTAINER) expect(helper.note_max_access_for_user(other_note)).to eq(Gitlab::Access::REPORTER) end end diff --git a/spec/helpers/time_helper_spec.rb b/spec/helpers/time_helper_spec.rb index 21f35585367..0b371d69ecf 100644 --- a/spec/helpers/time_helper_spec.rb +++ b/spec/helpers/time_helper_spec.rb @@ -4,10 +4,12 @@ describe TimeHelper do describe "#time_interval_in_words" do it "returns minutes and seconds" do intervals_in_words = { - 100 => "1 minute 40 seconds", - 100.32 => "1 minute 40 seconds", - 121 => "2 minutes 1 second", - 3721 => "62 minutes 1 second", + 60 => "1 minute", + 100 => "1 minute and 40 seconds", + 100.32 => "1 minute and 40 seconds", + 120 => "2 minutes", + 121 => "2 minutes and 1 second", + 3721 => "62 minutes and 1 second", 0 => "0 seconds" } diff --git a/spec/javascripts/diffs/components/changed_files_spec.js b/spec/javascripts/diffs/components/changed_files_spec.js index 2d57af6137c..f737e8fa38e 100644 --- a/spec/javascripts/diffs/components/changed_files_spec.js +++ b/spec/javascripts/diffs/components/changed_files_spec.js @@ -1,12 +1,17 @@ import Vue from 'vue'; -import $ from 'jquery'; +import Vuex from 'vuex'; import { mountComponentWithStore } from 'spec/helpers'; -import store from '~/diffs/store'; -import ChangedFiles from '~/diffs/components/changed_files.vue'; +import diffsModule from '~/diffs/store/modules'; +import changedFiles from '~/diffs/components/changed_files.vue'; describe('ChangedFiles', () => { - const Component = Vue.extend(ChangedFiles); - const createComponent = props => mountComponentWithStore(Component, { props, store }); + const Component = Vue.extend(changedFiles); + const store = new Vuex.Store({ + modules: { + diffs: diffsModule, + }, + }); + let vm; beforeEach(() => { @@ -14,6 +19,7 @@ describe('ChangedFiles', () => { <div id="dummy-element"></div> <div class="js-tabs-affix"></div> `); + const props = { diffFiles: [ { @@ -26,7 +32,8 @@ describe('ChangedFiles', () => { }, ], }; - vm = createComponent(props); + + vm = mountComponentWithStore(Component, { props, store }); }); describe('with single file added', () => { @@ -40,58 +47,56 @@ describe('ChangedFiles', () => { }); }); - describe('template', () => { - describe('diff view mode buttons', () => { - let inlineButton; - let parallelButton; + describe('diff view mode buttons', () => { + let inlineButton; + let parallelButton; - beforeEach(() => { - inlineButton = vm.$el.querySelector('.js-inline-diff-button'); - parallelButton = vm.$el.querySelector('.js-parallel-diff-button'); - }); + beforeEach(() => { + inlineButton = vm.$el.querySelector('.js-inline-diff-button'); + parallelButton = vm.$el.querySelector('.js-parallel-diff-button'); + }); + + it('should have Inline and Side-by-side buttons', () => { + expect(inlineButton).toBeDefined(); + expect(parallelButton).toBeDefined(); + }); + + it('should add active class to Inline button', done => { + vm.$store.state.diffs.diffViewType = 'inline'; + + vm.$nextTick(() => { + expect(inlineButton.classList.contains('active')).toEqual(true); + expect(parallelButton.classList.contains('active')).toEqual(false); - it('should have Inline and Side-by-side buttons', () => { - expect(inlineButton).toBeDefined(); - expect(parallelButton).toBeDefined(); + done(); }); + }); - it('should add active class to Inline button', done => { - vm.$store.state.diffs.diffViewType = 'inline'; + it('should toggle active state of buttons when diff view type changed', done => { + vm.$store.state.diffs.diffViewType = 'parallel'; - vm.$nextTick(() => { - expect(inlineButton.classList.contains('active')).toEqual(true); - expect(parallelButton.classList.contains('active')).toEqual(false); + vm.$nextTick(() => { + expect(inlineButton.classList.contains('active')).toEqual(false); + expect(parallelButton.classList.contains('active')).toEqual(true); - done(); - }); + done(); }); + }); - it('should toggle active state of buttons when diff view type changed', done => { - vm.$store.state.diffs.diffViewType = 'parallel'; + describe('clicking them', () => { + it('should toggle the diff view type', done => { + parallelButton.click(); vm.$nextTick(() => { expect(inlineButton.classList.contains('active')).toEqual(false); expect(parallelButton.classList.contains('active')).toEqual(true); - done(); - }); - }); - - describe('clicking them', () => { - it('should toggle the diff view type', done => { - $(parallelButton).click(); + inlineButton.click(); vm.$nextTick(() => { - expect(inlineButton.classList.contains('active')).toEqual(false); - expect(parallelButton.classList.contains('active')).toEqual(true); - - $(inlineButton).click(); - - vm.$nextTick(() => { - expect(inlineButton.classList.contains('active')).toEqual(true); - expect(parallelButton.classList.contains('active')).toEqual(false); - done(); - }); + expect(inlineButton.classList.contains('active')).toEqual(true); + expect(parallelButton.classList.contains('active')).toEqual(false); + done(); }); }); }); diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js index 05f5d47ce42..0f3a95da5bf 100644 --- a/spec/javascripts/diffs/components/diff_file_header_spec.js +++ b/spec/javascripts/diffs/components/diff_file_header_spec.js @@ -1,7 +1,10 @@ import Vue from 'vue'; +import Vuex from 'vuex'; +import diffsModule from '~/diffs/store/modules'; +import notesModule from '~/notes/stores/modules'; import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; const discussionFixture = 'merge_requests/diff_discussion.json'; @@ -9,6 +12,12 @@ describe('diff_file_header', () => { let vm; let props; const Component = Vue.extend(DiffFileHeader); + const store = new Vuex.Store({ + modules: { + diffs: diffsModule, + notes: notesModule, + }, + }); beforeEach(() => { const diffDiscussionMock = getJSONFixture(discussionFixture)[0]; @@ -26,13 +35,13 @@ describe('diff_file_header', () => { describe('computed', () => { describe('icon', () => { beforeEach(() => { - props.diffFile.blob.icon = 'dummy icon'; + props.diffFile.blob.icon = 'file-text-o'; }); it('returns the blob icon for files', () => { props.diffFile.submodule = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.icon).toBe(props.diffFile.blob.icon); }); @@ -40,7 +49,7 @@ describe('diff_file_header', () => { it('returns the archive icon for submodules', () => { props.diffFile.submodule = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.icon).toBe('archive'); }); @@ -58,7 +67,7 @@ describe('diff_file_header', () => { it('returns the fileHash for files', () => { props.diffFile.submodule = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.titleLink).toBe(`#${props.diffFile.fileHash}`); }); @@ -66,7 +75,7 @@ describe('diff_file_header', () => { it('returns the submoduleTreeUrl for submodules', () => { props.diffFile.submodule = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.titleLink).toBe(props.diffFile.submoduleTreeUrl); }); @@ -77,7 +86,7 @@ describe('diff_file_header', () => { submoduleTreeUrl: null, }); - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.titleLink).toBe(props.diffFile.submoduleLink); }); @@ -94,7 +103,7 @@ describe('diff_file_header', () => { it('returns the filePath for files', () => { props.diffFile.submodule = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.filePath).toBe(props.diffFile.filePath); }); @@ -102,7 +111,7 @@ describe('diff_file_header', () => { it('appends the truncated blob id for submodules', () => { props.diffFile.submodule = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.filePath).toBe( `${props.diffFile.filePath} @ ${props.diffFile.blob.id.substr(0, 8)}`, @@ -114,7 +123,7 @@ describe('diff_file_header', () => { it('returns a link tag if fileHash is set', () => { props.diffFile.fileHash = 'some hash'; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.titleTag).toBe('a'); }); @@ -122,7 +131,7 @@ describe('diff_file_header', () => { it('returns a span tag if fileHash is not set', () => { props.diffFile.fileHash = null; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.titleTag).toBe('span'); }); @@ -137,7 +146,7 @@ describe('diff_file_header', () => { }); it('returns true if file is stored in LFS', () => { - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.isUsingLfs).toBe(true); }); @@ -145,7 +154,7 @@ describe('diff_file_header', () => { it('returns false if file is not stored externally', () => { props.diffFile.storedExternally = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.isUsingLfs).toBe(false); }); @@ -153,7 +162,7 @@ describe('diff_file_header', () => { it('returns false if file is not stored in LFS', () => { props.diffFile.externalStorage = 'not lfs'; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.isUsingLfs).toBe(false); }); @@ -163,7 +172,7 @@ describe('diff_file_header', () => { it('returns chevron-down if the diff is expanded', () => { props.expanded = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.collapseIcon).toBe('chevron-down'); }); @@ -171,49 +180,18 @@ describe('diff_file_header', () => { it('returns chevron-right if the diff is collapsed', () => { props.expanded = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.collapseIcon).toBe('chevron-right'); }); }); - describe('isDiscussionsExpanded', () => { - beforeEach(() => { - Object.assign(props, { - discussionsExpanded: true, - expanded: true, - }); - }); - - it('returns true if diff and discussion are expanded', () => { - vm = mountComponent(Component, props); - - expect(vm.isDiscussionsExpanded).toBe(true); - }); - - it('returns false if discussion is collapsed', () => { - props.discussionsExpanded = false; - - vm = mountComponent(Component, props); - - expect(vm.isDiscussionsExpanded).toBe(false); - }); - - it('returns false if diff is collapsed', () => { - props.expanded = false; - - vm = mountComponent(Component, props); - - expect(vm.isDiscussionsExpanded).toBe(false); - }); - }); - describe('viewFileButtonText', () => { it('contains the truncated content SHA', () => { const dummySha = 'deebd00f is no SHA'; props.diffFile.contentSha = dummySha; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.viewFileButtonText).not.toContain(dummySha); expect(vm.viewFileButtonText).toContain(dummySha.substr(0, 8)); @@ -225,7 +203,7 @@ describe('diff_file_header', () => { const dummySha = 'deadabba sings no more'; props.diffFile.diffRefs.baseSha = dummySha; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.viewReplacedFileButtonText).not.toContain(dummySha); expect(vm.viewReplacedFileButtonText).toContain(dummySha.substr(0, 8)); @@ -234,25 +212,25 @@ describe('diff_file_header', () => { }); describe('methods', () => { - describe('handleToggle', () => { + describe('handleToggleFile', () => { beforeEach(() => { spyOn(vm, '$emit').and.stub(); }); it('emits toggleFile if checkTarget is false', () => { - vm.handleToggle(null, false); + vm.handleToggleFile(null, false); expect(vm.$emit).toHaveBeenCalledWith('toggleFile'); }); it('emits toggleFile if checkTarget is true and event target is header', () => { - vm.handleToggle({ target: vm.$refs.header }, true); + vm.handleToggleFile({ target: vm.$refs.header }, true); expect(vm.$emit).toHaveBeenCalledWith('toggleFile'); }); it('does not emit toggleFile if checkTarget is true and event target is not header', () => { - vm.handleToggle({ target: 'not header' }, true); + vm.handleToggleFile({ target: 'not header' }, true); expect(vm.$emit).not.toHaveBeenCalled(); }); @@ -266,7 +244,7 @@ describe('diff_file_header', () => { it('is visible if collapsible is true', () => { props.collapsible = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(collapseToggle()).not.toBe(null); }); @@ -274,14 +252,14 @@ describe('diff_file_header', () => { it('is hidden if collapsible is false', () => { props.collapsible = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(collapseToggle()).toBe(null); }); }); it('displays an file icon in the title', () => { - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector('svg.js-file-icon use').getAttribute('xlink:href')).toContain( 'ruby', ); @@ -293,7 +271,7 @@ describe('diff_file_header', () => { it('displays the path of a added file', () => { props.diffFile.renamedFile = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(filePaths()).toHaveLength(1); expect(filePaths()[0]).toHaveText(props.diffFile.filePath); @@ -303,7 +281,7 @@ describe('diff_file_header', () => { props.diffFile.renamedFile = false; props.diffFile.deletedFile = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(filePaths()).toHaveLength(1); expect(filePaths()[0]).toHaveText(`${props.diffFile.filePath} deleted`); @@ -312,7 +290,7 @@ describe('diff_file_header', () => { it('displays old and new path if the file was renamed', () => { props.diffFile.renamedFile = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(filePaths()).toHaveLength(2); expect(filePaths()[0]).toHaveText(props.diffFile.oldPath); @@ -321,7 +299,7 @@ describe('diff_file_header', () => { }); it('displays a copy to clipboard button', () => { - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); const button = vm.$el.querySelector('.btn-clipboard'); expect(button).not.toBe(null); @@ -332,7 +310,7 @@ describe('diff_file_header', () => { it('it displays old and new file mode if it changed', () => { props.diffFile.modeChanged = true; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); const { fileMode } = vm.$refs; expect(fileMode).not.toBe(undefined); @@ -343,7 +321,7 @@ describe('diff_file_header', () => { it('does not display the file mode if it has not changed', () => { props.diffFile.modeChanged = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); const { fileMode } = vm.$refs; expect(fileMode).toBe(undefined); @@ -359,7 +337,7 @@ describe('diff_file_header', () => { externalStorage: 'lfs', }); - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(lfsLabel()).not.toBe(null); expect(lfsLabel()).toHaveText('LFS'); @@ -368,7 +346,7 @@ describe('diff_file_header', () => { it('does not display the LFS label for files stored in repository', () => { props.diffFile.storedExternally = false; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(lfsLabel()).toBe(null); }); @@ -376,7 +354,7 @@ describe('diff_file_header', () => { describe('edit button', () => { it('should not render edit button if addMergeRequestButtons is not true', () => { - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector('.js-edit-blob')).toEqual(null); }); @@ -384,7 +362,7 @@ describe('diff_file_header', () => { it('should show edit button when file is editable', () => { props.addMergeRequestButtons = true; props.diffFile.editPath = '/'; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector('.js-edit-blob')).toContainText('Edit'); }); @@ -393,7 +371,7 @@ describe('diff_file_header', () => { props.addMergeRequestButtons = true; props.diffFile.deletedFile = true; props.diffFile.editPath = '/'; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector('.js-edit-blob')).toEqual(null); }); @@ -413,7 +391,7 @@ describe('diff_file_header', () => { props.diffFile.externalUrl = url; props.diffFile.formattedExternalUrl = title; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector(`a[href="${url}"]`)).not.toBe(null); expect(vm.$el.querySelector(`a[data-original-title="View on ${title}"]`)).not.toBe(null); @@ -423,11 +401,39 @@ describe('diff_file_header', () => { props.diffFile.externalUrl = ''; props.diffFile.formattedExternalUrl = title; - vm = mountComponent(Component, props); + vm = mountComponentWithStore(Component, { props, store }); expect(vm.$el.querySelector(`a[data-original-title="View on ${title}"]`)).toBe(null); }); }); }); + + describe('handles toggle discussions', () => { + it('dispatches toggleFileDiscussions when user clicks on toggle discussions button', () => { + const propsCopy = Object.assign({}, props); + propsCopy.diffFile.submodule = false; + propsCopy.diffFile.blob = { + id: '848ed9407c6730ff16edb3dd24485a0eea24292a', + path: 'lib/base.js', + name: 'base.js', + mode: '100644', + readableText: true, + icon: 'file-text-o', + }; + propsCopy.addMergeRequestButtons = true; + propsCopy.diffFile.deletedFile = true; + + vm = mountComponentWithStore(Component, { + props: propsCopy, + store, + }); + + spyOn(vm, 'toggleFileDiscussions'); + + vm.$el.querySelector('.js-btn-vue-toggle-comments').click(); + + expect(vm.toggleFileDiscussions).toHaveBeenCalled(); + }); + }); }); }); diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 6829c1e956a..c1560dac1a0 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -191,4 +191,48 @@ describe('DiffsStoreActions', () => { ); }); }); + + describe('toggleFileDiscussions', () => { + it('should dispatch collapseDiscussion when all discussions are expanded', () => { + const getters = { + getDiffFileDiscussions: jasmine.createSpy().and.returnValue([{ id: 1 }]), + diffHasAllExpandedDiscussions: jasmine.createSpy().and.returnValue(true), + diffHasAllCollpasedDiscussions: jasmine.createSpy().and.returnValue(false), + }; + + const dispatch = jasmine.createSpy('dispatch'); + + actions.toggleFileDiscussions({ getters, dispatch }); + + expect(dispatch).toHaveBeenCalledWith('collapseDiscussion', { discussionId: 1 }, { root: true }); + }); + + it('should dispatch expandDiscussion when all discussions are collapsed', () => { + const getters = { + getDiffFileDiscussions: jasmine.createSpy().and.returnValue([{ id: 1 }]), + diffHasAllExpandedDiscussions: jasmine.createSpy().and.returnValue(false), + diffHasAllCollpasedDiscussions: jasmine.createSpy().and.returnValue(true), + }; + + const dispatch = jasmine.createSpy(); + + actions.toggleFileDiscussions({ getters, dispatch }); + + expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true }); + }); + + it('should dispatch expandDiscussion when some discussions are collapsed and others are expanded for the collapsed discussion', () => { + const getters = { + getDiffFileDiscussions: jasmine.createSpy().and.returnValue([{ expanded: false, id: 1 }]), + diffHasAllExpandedDiscussions: jasmine.createSpy().and.returnValue(false), + diffHasAllCollpasedDiscussions: jasmine.createSpy().and.returnValue(false), + }; + + const dispatch = jasmine.createSpy(); + + actions.toggleFileDiscussions({ getters, dispatch }); + + expect(dispatch).toHaveBeenCalledWith('expandDiscussion', { discussionId: 1 }, { root: true }); + }); + }); }); diff --git a/spec/javascripts/diffs/store/getters_spec.js b/spec/javascripts/diffs/store/getters_spec.js index 7a94f18778b..919b612bb6a 100644 --- a/spec/javascripts/diffs/store/getters_spec.js +++ b/spec/javascripts/diffs/store/getters_spec.js @@ -1,12 +1,24 @@ import * as getters from '~/diffs/store/getters'; import state from '~/diffs/store/modules/diff_state'; import { PARALLEL_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; +import discussion from '../mock_data/diff_discussions'; -describe('DiffsStoreGetters', () => { +describe('Diffs Module Getters', () => { let localState; + let discussionMock; + let discussionMock1; + + const diffFileMock = { + fileHash: '9732849daca6ae818696d9575f5d1207d1a7f8bb', + }; beforeEach(() => { localState = state(); + discussionMock = Object.assign({}, discussion); + discussionMock.diff_file.file_hash = diffFileMock.fileHash; + + discussionMock1 = Object.assign({}, discussion); + discussionMock1.diff_file.file_hash = diffFileMock.fileHash; }); describe('isParallelView', () => { @@ -63,4 +75,113 @@ describe('DiffsStoreGetters', () => { expect(getters.commitId(localState)).toEqual(null); }); }); + + describe('diffHasAllExpandedDiscussions', () => { + it('returns true when all discussions are expanded', () => { + expect( + getters.diffHasAllExpandedDiscussions(localState, { + getDiffFileDiscussions: () => [discussionMock, discussionMock], + })(diffFileMock), + ).toEqual(true); + }); + + it('returns false when there are no discussions', () => { + expect( + getters.diffHasAllExpandedDiscussions(localState, { + getDiffFileDiscussions: () => [], + })(diffFileMock), + ).toEqual(false); + }); + + it('returns false when one discussions is collapsed', () => { + discussionMock1.expanded = false; + + expect( + getters.diffHasAllExpandedDiscussions(localState, { + getDiffFileDiscussions: () => [discussionMock, discussionMock1], + })(diffFileMock), + ).toEqual(false); + }); + }); + + describe('diffHasAllCollpasedDiscussions', () => { + it('returns true when all discussions are collapsed', () => { + discussionMock.diff_file.file_hash = diffFileMock.fileHash; + discussionMock.expanded = false; + + expect( + getters.diffHasAllCollpasedDiscussions(localState, { + getDiffFileDiscussions: () => [discussionMock], + })(diffFileMock), + ).toEqual(true); + }); + + it('returns false when there are no discussions', () => { + expect( + getters.diffHasAllCollpasedDiscussions(localState, { + getDiffFileDiscussions: () => [], + })(diffFileMock), + ).toEqual(false); + }); + + it('returns false when one discussions is expanded', () => { + discussionMock1.expanded = false; + + expect( + getters.diffHasAllCollpasedDiscussions(localState, { + getDiffFileDiscussions: () => [discussionMock, discussionMock1], + })(diffFileMock), + ).toEqual(false); + }); + }); + + describe('diffHasExpandedDiscussions', () => { + it('returns true when one of the discussions is expanded', () => { + discussionMock1.expanded = false; + + expect( + getters.diffHasExpandedDiscussions(localState, { + getDiffFileDiscussions: () => [discussionMock, discussionMock], + })(diffFileMock), + ).toEqual(true); + }); + + it('returns false when there are no discussions', () => { + expect( + getters.diffHasExpandedDiscussions(localState, { getDiffFileDiscussions: () => [] })( + diffFileMock, + ), + ).toEqual(false); + }); + + it('returns false when no discussion is expanded', () => { + discussionMock.expanded = false; + discussionMock1.expanded = false; + + expect( + getters.diffHasExpandedDiscussions(localState, { + getDiffFileDiscussions: () => [discussionMock, discussionMock1], + })(diffFileMock), + ).toEqual(false); + }); + }); + + describe('getDiffFileDiscussions', () => { + it('returns an array with discussions when fileHash matches and the discussion belongs to a diff', () => { + discussionMock.diff_file.file_hash = diffFileMock.fileHash; + + expect( + getters.getDiffFileDiscussions(localState, {}, {}, { discussions: [discussionMock] })( + diffFileMock, + ).length, + ).toEqual(1); + }); + + it('returns an empty array when no discussions are found in the given diff', () => { + expect( + getters.getDiffFileDiscussions(localState, {}, {}, { discussions: [] })(diffFileMock) + .length, + ).toEqual(0); + }); + }); }); diff --git a/spec/javascripts/environments/environment_rollback_spec.js b/spec/javascripts/environments/environment_rollback_spec.js index eb8e49d81fe..79f33c5bc8a 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js +++ b/spec/javascripts/environments/environment_rollback_spec.js @@ -18,7 +18,7 @@ describe('Rollback Component', () => { }, }).$mount(); - expect(component.$el.querySelector('span').textContent).toContain('Re-deploy'); + expect(component.$el).toHaveSpriteIcon('repeat'); }); it('Should render Rollback label when isLastDeployment is false', () => { @@ -30,6 +30,6 @@ describe('Rollback Component', () => { }, }).$mount(); - expect(component.$el.querySelector('span').textContent).toContain('Rollback'); + expect(component.$el).toHaveSpriteIcon('redo'); }); }); diff --git a/spec/javascripts/environments/environment_stop_spec.js b/spec/javascripts/environments/environment_stop_spec.js index 3f95faf466a..4d9caa57566 100644 --- a/spec/javascripts/environments/environment_stop_spec.js +++ b/spec/javascripts/environments/environment_stop_spec.js @@ -4,7 +4,6 @@ import stopComp from '~/environments/components/environment_stop.vue'; describe('Stop Component', () => { let StopComponent; let component; - const stopURL = '/stop'; beforeEach(() => { StopComponent = Vue.extend(stopComp); @@ -12,20 +11,13 @@ describe('Stop Component', () => { component = new StopComponent({ propsData: { - stopUrl: stopURL, + environment: {}, }, }).$mount(); }); - describe('computed', () => { - it('title', () => { - expect(component.title).toEqual('Stop'); - }); - }); - it('should render a button to stop the environment', () => { expect(component.$el.tagName).toEqual('BUTTON'); - expect(component.$el.getAttribute('data-original-title')).toEqual('Stop'); - expect(component.$el.getAttribute('aria-label')).toEqual('Stop'); + expect(component.$el.getAttribute('data-original-title')).toEqual('Stop environment'); }); }); diff --git a/spec/javascripts/fixtures/commit.rb b/spec/javascripts/fixtures/commit.rb index 351db6ba184..24ab8159a18 100644 --- a/spec/javascripts/fixtures/commit.rb +++ b/spec/javascripts/fixtures/commit.rb @@ -14,7 +14,7 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller end before do - project.add_master(user) + project.add_maintainer(user) sign_in(user) end diff --git a/spec/javascripts/fixtures/groups.rb b/spec/javascripts/fixtures/groups.rb index 35be52fbf97..a2035ceae15 100644 --- a/spec/javascripts/fixtures/groups.rb +++ b/spec/javascripts/fixtures/groups.rb @@ -13,7 +13,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do end before do - group.add_master(admin) + group.add_maintainer(admin) sign_in(admin) end diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index e8865b04874..57c78182abc 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -17,7 +17,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do end before do - project.add_master(admin) + project.add_maintainer(admin) sign_in(admin) end diff --git a/spec/javascripts/helpers/wait_for_promises.js b/spec/javascripts/helpers/wait_for_promises.js new file mode 100644 index 00000000000..1d2b53fc770 --- /dev/null +++ b/spec/javascripts/helpers/wait_for_promises.js @@ -0,0 +1 @@ +export default () => new Promise(resolve => requestAnimationFrame(resolve)); diff --git a/spec/javascripts/ide/components/new_dropdown/button_spec.js b/spec/javascripts/ide/components/new_dropdown/button_spec.js new file mode 100644 index 00000000000..ef083d06ba7 --- /dev/null +++ b/spec/javascripts/ide/components/new_dropdown/button_spec.js @@ -0,0 +1,49 @@ +import Vue from 'vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import Button from '~/ide/components/new_dropdown/button.vue'; + +describe('IDE new entry dropdown button component', () => { + let Component; + let vm; + + beforeAll(() => { + Component = Vue.extend(Button); + }); + + beforeEach(() => { + vm = mountComponent(Component, { + label: 'Testing', + icon: 'doc-new', + }); + + spyOn(vm, '$emit'); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders button with label', () => { + expect(vm.$el.textContent).toContain('Testing'); + }); + + it('renders icon', () => { + expect(vm.$el.querySelector('.ic-doc-new')).not.toBe(null); + }); + + it('emits click event', () => { + vm.$el.click(); + + expect(vm.$emit).toHaveBeenCalledWith('click'); + }); + + it('hides label if showLabel is false', done => { + vm.showLabel = false; + + vm.$nextTick(() => { + expect(vm.$el.textContent).not.toContain('Testing'); + + done(); + }); + }); +}); diff --git a/spec/javascripts/ide/components/new_dropdown/index_spec.js b/spec/javascripts/ide/components/new_dropdown/index_spec.js index 7b637f37eba..4d704b80209 100644 --- a/spec/javascripts/ide/components/new_dropdown/index_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/index_spec.js @@ -13,6 +13,7 @@ describe('new dropdown component', () => { vm = createComponentWithStore(component, store, { branch: 'master', path: '', + mouseOver: false, }); vm.$store.state.currentProjectId = 'abcproject'; @@ -21,6 +22,8 @@ describe('new dropdown component', () => { tree: [], }; + spyOn(vm, 'openNewEntryModal'); + vm.$mount(); }); @@ -31,50 +34,23 @@ describe('new dropdown component', () => { }); it('renders new file, upload and new directory links', () => { - expect(vm.$el.querySelectorAll('a')[0].textContent.trim()).toBe('New file'); - expect(vm.$el.querySelectorAll('a')[1].textContent.trim()).toBe('Upload file'); - expect(vm.$el.querySelectorAll('a')[2].textContent.trim()).toBe('New directory'); + const buttons = vm.$el.querySelectorAll('.dropdown-menu button'); + expect(buttons[0].textContent.trim()).toBe('New file'); + expect(buttons[1].textContent.trim()).toBe('Upload file'); + expect(buttons[2].textContent.trim()).toBe('New directory'); }); describe('createNewItem', () => { it('sets modalType to blob when new file is clicked', () => { - vm.$el.querySelectorAll('a')[0].click(); + vm.$el.querySelectorAll('.dropdown-menu button')[0].click(); - expect(vm.modalType).toBe('blob'); + expect(vm.openNewEntryModal).toHaveBeenCalledWith({ type: 'blob', path: '' }); }); it('sets modalType to tree when new directory is clicked', () => { - vm.$el.querySelectorAll('a')[2].click(); - - expect(vm.modalType).toBe('tree'); - }); - - it('opens modal when link is clicked', done => { - vm.$el.querySelectorAll('a')[0].click(); - - Vue.nextTick(() => { - expect(vm.$el.querySelector('.modal')).not.toBeNull(); - - done(); - }); - }); - }); - - describe('hideModal', () => { - beforeAll(done => { - vm.openModal = true; - Vue.nextTick(done); - }); - - it('closes modal after toggling', done => { - vm.hideModal(); + vm.$el.querySelectorAll('.dropdown-menu button')[2].click(); - Vue.nextTick() - .then(() => { - expect(vm.$el.querySelector('.modal')).toBeNull(); - }) - .then(done) - .catch(done.fail); + expect(vm.openNewEntryModal).toHaveBeenCalledWith({ type: 'tree', path: '' }); }); }); diff --git a/spec/javascripts/ide/components/new_dropdown/modal_spec.js b/spec/javascripts/ide/components/new_dropdown/modal_spec.js index f362ed4db65..6dcc5880677 100644 --- a/spec/javascripts/ide/components/new_dropdown/modal_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/modal_spec.js @@ -1,6 +1,7 @@ import Vue from 'vue'; +import { createStore } from '~/ide/stores'; import modal from '~/ide/components/new_dropdown/modal.vue'; -import createComponent from 'spec/helpers/vue_mount_component_helper'; +import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; describe('new file modal component', () => { const Component = Vue.extend(modal); @@ -13,13 +14,15 @@ describe('new file modal component', () => { ['tree', 'blob'].forEach(type => { describe(type, () => { beforeEach(() => { - vm = createComponent(Component, { + const store = createStore(); + store.state.newEntryModal = { type, - branchId: 'master', path: '', - }); + }; + + vm = createComponentWithStore(Component, store).$mount(); - vm.entryName = 'testing'; + vm.name = 'testing'; }); it(`sets modal title as ${type}`, () => { @@ -40,12 +43,11 @@ describe('new file modal component', () => { describe('createEntryInStore', () => { it('$emits create', () => { - spyOn(vm, '$emit'); + spyOn(vm, 'createTempEntry'); vm.createEntryInStore(); - expect(vm.$emit).toHaveBeenCalledWith('create', { - branchId: 'master', + expect(vm.createTempEntry).toHaveBeenCalledWith({ name: 'testing', type, }); @@ -53,22 +55,4 @@ describe('new file modal component', () => { }); }); }); - - it('focuses field on mount', () => { - document.body.innerHTML += '<div class="js-test"></div>'; - - vm = createComponent( - Component, - { - type: 'tree', - branchId: 'master', - path: '', - }, - '.js-test', - ); - - expect(document.activeElement).toBe(vm.$refs.fieldName); - - vm.$el.remove(); - }); }); diff --git a/spec/javascripts/ide/components/new_dropdown/upload_spec.js b/spec/javascripts/ide/components/new_dropdown/upload_spec.js index 2bc5d701601..9c76500cfe5 100644 --- a/spec/javascripts/ide/components/new_dropdown/upload_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/upload_spec.js @@ -9,7 +9,6 @@ describe('new dropdown upload', () => { const Component = Vue.extend(upload); vm = createComponent(Component, { - branchId: 'master', path: '', }); @@ -65,7 +64,6 @@ describe('new dropdown upload', () => { expect(vm.$emit).toHaveBeenCalledWith('create', { name: file.name, - branchId: 'master', type: 'blob', content: target.result, base64: false, @@ -77,7 +75,6 @@ describe('new dropdown upload', () => { expect(vm.$emit).toHaveBeenCalledWith('create', { name: file.name, - branchId: 'master', type: 'blob', content: binaryTarget.result.split('base64,')[1], base64: true, diff --git a/spec/javascripts/issuable_time_tracker_spec.js b/spec/javascripts/issuable_time_tracker_spec.js deleted file mode 100644 index 5add150f874..00000000000 --- a/spec/javascripts/issuable_time_tracker_spec.js +++ /dev/null @@ -1,201 +0,0 @@ -/* eslint-disable no-unused-vars, func-call-spacing, no-spaced-func, semi, quotes, space-infix-ops, max-len */ - -import $ from 'jquery'; -import Vue from 'vue'; - -import timeTracker from '~/sidebar/components/time_tracking/time_tracker.vue'; - -function initTimeTrackingComponent(opts) { - setFixtures(` - <div> - <div id="mock-container"></div> - </div> - `); - - this.initialData = { - time_estimate: opts.timeEstimate, - time_spent: opts.timeSpent, - human_time_estimate: opts.timeEstimateHumanReadable, - human_time_spent: opts.timeSpentHumanReadable, - rootPath: '/', - }; - - const TimeTrackingComponent = Vue.extend(timeTracker); - this.timeTracker = new TimeTrackingComponent({ - el: '#mock-container', - propsData: this.initialData, - }); -} - -describe('Issuable Time Tracker', function() { - describe('Initialization', function() { - beforeEach(function() { - initTimeTrackingComponent.call(this, { timeEstimate: 100000, timeSpent: 5000, timeEstimateHumanReadable: '2h 46m', timeSpentHumanReadable: '1h 23m' }); - }); - - it('should return something defined', function() { - expect(this.timeTracker).toBeDefined(); - }); - - it ('should correctly set timeEstimate', function(done) { - Vue.nextTick(() => { - expect(this.timeTracker.timeEstimate).toBe(this.initialData.time_estimate); - done(); - }); - }); - it ('should correctly set time_spent', function(done) { - Vue.nextTick(() => { - expect(this.timeTracker.timeSpent).toBe(this.initialData.time_spent); - done(); - }); - }); - }); - - describe('Content Display', function() { - describe('Panes', function() { - describe('Comparison pane', function() { - beforeEach(function() { - initTimeTrackingComponent.call(this, { timeEstimate: 100000, timeSpent: 5000, timeEstimateHumanReadable: '', timeSpentHumanReadable: '' }); - }); - - it('should show the "Comparison" pane when timeEstimate and time_spent are truthy', function(done) { - Vue.nextTick(() => { - const $comparisonPane = this.timeTracker.$el.querySelector('.time-tracking-comparison-pane'); - expect(this.timeTracker.showComparisonState).toBe(true); - done(); - }); - }); - - describe('Remaining meter', function() { - it('should display the remaining meter with the correct width', function(done) { - Vue.nextTick(() => { - const meterWidth = this.timeTracker.$el.querySelector('.time-tracking-comparison-pane .meter-fill').style.width; - const correctWidth = '5%'; - - expect(meterWidth).toBe(correctWidth); - done(); - }) - }); - - it('should display the remaining meter with the correct background color when within estimate', function(done) { - Vue.nextTick(() => { - const styledMeter = $(this.timeTracker.$el).find('.time-tracking-comparison-pane .within_estimate .meter-fill'); - expect(styledMeter.length).toBe(1); - done() - }); - }); - - it('should display the remaining meter with the correct background color when over estimate', function(done) { - this.timeTracker.time_estimate = 100000; - this.timeTracker.time_spent = 20000000; - Vue.nextTick(() => { - const styledMeter = $(this.timeTracker.$el).find('.time-tracking-comparison-pane .over_estimate .meter-fill'); - expect(styledMeter.length).toBe(1); - done(); - }); - }); - }); - }); - - describe("Estimate only pane", function() { - beforeEach(function() { - initTimeTrackingComponent.call(this, { timeEstimate: 100000, timeSpent: 0, timeEstimateHumanReadable: '2h 46m', timeSpentHumanReadable: '' }); - }); - - it('should display the human readable version of time estimated', function(done) { - Vue.nextTick(() => { - const estimateText = this.timeTracker.$el.querySelector('.time-tracking-estimate-only-pane').innerText; - const correctText = 'Estimated: 2h 46m'; - - expect(estimateText).toBe(correctText); - done(); - }); - }); - }); - - describe('Spent only pane', function() { - beforeEach(function() { - initTimeTrackingComponent.call(this, { timeEstimate: 0, timeSpent: 5000, timeEstimateHumanReadable: '2h 46m', timeSpentHumanReadable: '1h 23m' }); - }); - - it('should display the human readable version of time spent', function(done) { - Vue.nextTick(() => { - const spentText = this.timeTracker.$el.querySelector('.time-tracking-spend-only-pane').innerText; - const correctText = 'Spent: 1h 23m'; - - expect(spentText).toBe(correctText); - done(); - }); - }); - }); - - describe('No time tracking pane', function() { - beforeEach(function() { - initTimeTrackingComponent.call(this, { timeEstimate: 0, timeSpent: 0, timeEstimateHumanReadable: '', timeSpentHumanReadable: '' }); - }); - - it('should only show the "No time tracking" pane when both timeEstimate and time_spent are falsey', function(done) { - Vue.nextTick(() => { - const $noTrackingPane = this.timeTracker.$el.querySelector('.time-tracking-no-tracking-pane'); - const noTrackingText =$noTrackingPane.innerText; - const correctText = 'No estimate or time spent'; - - expect(this.timeTracker.showNoTimeTrackingState).toBe(true); - expect($noTrackingPane).toBeVisible(); - expect(noTrackingText).toBe(correctText); - done(); - }); - }); - }); - - describe("Help pane", function() { - beforeEach(function() { - initTimeTrackingComponent.call(this, { timeEstimate: 0, timeSpent: 0 }); - }); - - it('should not show the "Help" pane by default', function(done) { - Vue.nextTick(() => { - const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state'); - - expect(this.timeTracker.showHelpState).toBe(false); - expect($helpPane).toBeNull(); - done(); - }); - }); - - it('should show the "Help" pane when help button is clicked', function(done) { - Vue.nextTick(() => { - $(this.timeTracker.$el).find('.help-button').click(); - - setTimeout(() => { - const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state'); - expect(this.timeTracker.showHelpState).toBe(true); - expect($helpPane).toBeVisible(); - done(); - }, 10); - }); - }); - - it('should not show the "Help" pane when help button is clicked and then closed', function(done) { - Vue.nextTick(() => { - $(this.timeTracker.$el).find('.help-button').click(); - - setTimeout(() => { - - $(this.timeTracker.$el).find('.close-help-button').click(); - - setTimeout(() => { - const $helpPane = this.timeTracker.$el.querySelector('.time-tracking-help-state'); - - expect(this.timeTracker.showHelpState).toBe(false); - expect($helpPane).toBeNull(); - - done(); - }, 1000); - }, 1000); - }); - }); - }); - }); - }); -}); diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js index 79e375aa02e..2fcb5566ebc 100644 --- a/spec/javascripts/job_spec.js +++ b/spec/javascripts/job_spec.js @@ -5,6 +5,7 @@ import { numberToHumanSize } from '~/lib/utils/number_utils'; import '~/lib/utils/datetime_utility'; import Job from '~/job'; import '~/breakpoints'; +import waitForPromises from 'spec/helpers/wait_for_promises'; describe('Job', () => { const JOB_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`; @@ -12,10 +13,6 @@ describe('Job', () => { let response; let job; - function waitForPromise() { - return new Promise(resolve => requestAnimationFrame(resolve)); - } - preloadFixtures('builds/build-with-artifacts.html.raw'); beforeEach(() => { @@ -49,7 +46,7 @@ describe('Job', () => { beforeEach(function (done) { job = new Job(); - waitForPromise() + waitForPromises() .then(done) .catch(done.fail); }); @@ -93,7 +90,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(() => { expect($('#build-trace .js-build-output').text()).toMatch(/Update/); expect(job.state).toBe('newstate'); @@ -107,7 +104,7 @@ describe('Job', () => { }; }) .then(() => jasmine.clock().tick(4001)) - .then(waitForPromise) + .then(waitForPromises) .then(() => { expect($('#build-trace .js-build-output').text()).toMatch(/UpdateMore/); expect(job.state).toBe('finalstate'); @@ -126,7 +123,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(() => { expect($('#build-trace .js-build-output').text()).toMatch(/Update/); @@ -137,7 +134,7 @@ describe('Job', () => { }; }) .then(() => jasmine.clock().tick(4001)) - .then(waitForPromise) + .then(waitForPromises) .then(() => { expect($('#build-trace .js-build-output').text()).not.toMatch(/Update/); expect($('#build-trace .js-build-output').text()).toMatch(/Different/); @@ -160,7 +157,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(() => { expect(document.querySelector('.js-truncated-info').classList).not.toContain('hidden'); }) @@ -181,7 +178,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(() => { expect( document.querySelector('.js-truncated-info-size').textContent.trim(), @@ -203,7 +200,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(() => { expect( document.querySelector('.js-truncated-info-size').textContent.trim(), @@ -219,7 +216,7 @@ describe('Job', () => { }; }) .then(() => jasmine.clock().tick(4001)) - .then(waitForPromise) + .then(waitForPromises) .then(() => { expect( document.querySelector('.js-truncated-info-size').textContent.trim(), @@ -258,7 +255,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(() => { expect(document.querySelector('.js-truncated-info').classList).toContain('hidden'); }) @@ -280,7 +277,7 @@ describe('Job', () => { job = new Job(); - waitForPromise() + waitForPromises() .then(done) .catch(done.fail); }); diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js index 71ef3aa9b03..b66e8e1ceb3 100644 --- a/spec/javascripts/notes/stores/actions_spec.js +++ b/spec/javascripts/notes/stores/actions_spec.js @@ -128,6 +128,19 @@ describe('Actions Notes Store', () => { }); }); + describe('collapseDiscussion', () => { + it('should commit collapse discussion', done => { + testAction( + actions.collapseDiscussion, + { discussionId: discussionMock.id }, + { notes: [discussionMock] }, + [{ type: 'COLLAPSE_DISCUSSION', payload: { discussionId: discussionMock.id } }], + [], + done, + ); + }); + }); + describe('async methods', () => { const interceptor = (request, next) => { next( diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/javascripts/notes/stores/mutation_spec.js index ccc7328447b..a15ff1a5888 100644 --- a/spec/javascripts/notes/stores/mutation_spec.js +++ b/spec/javascripts/notes/stores/mutation_spec.js @@ -74,6 +74,20 @@ describe('Notes Store mutations', () => { }); }); + describe('COLLAPSE_DISCUSSION', () => { + it('should collpase an expanded discussion', () => { + const discussion = Object.assign({}, discussionMock, { expanded: true }); + + const state = { + discussions: [discussion], + }; + + mutations.COLLAPSE_DISCUSSION(state, { discussionId: discussion.id }); + + expect(state.discussions[0].expanded).toEqual(false); + }); + }); + describe('REMOVE_PLACEHOLDER_NOTES', () => { it('should remove all placeholder notes in indivudal notes and discussion', () => { const placeholderNote = Object.assign({}, individualNote, { isPlaceholderNote: true }); diff --git a/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js b/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js new file mode 100644 index 00000000000..b58de607ece --- /dev/null +++ b/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js @@ -0,0 +1,243 @@ +import $ from 'jquery'; +import Vue from 'vue'; + +import TimeTracker from '~/sidebar/components/time_tracking/time_tracker.vue'; + +import mountComponent from 'spec/helpers/vue_mount_component_helper'; + +describe('Issuable Time Tracker', () => { + let initialData; + let vm; + + const initTimeTrackingComponent = opts => { + setFixtures(` + <div> + <div id="mock-container"></div> + </div> + `); + + initialData = { + time_estimate: opts.timeEstimate, + time_spent: opts.timeSpent, + human_time_estimate: opts.timeEstimateHumanReadable, + human_time_spent: opts.timeSpentHumanReadable, + rootPath: '/', + }; + + const TimeTrackingComponent = Vue.extend({ + ...TimeTracker, + components: { + ...TimeTracker.components, + transition: { + // disable animations + template: '<div><slot></slot></div>', + }, + }, + }); + vm = mountComponent(TimeTrackingComponent, initialData, '#mock-container'); + }; + + afterEach(() => { + vm.$destroy(); + }); + + describe('Initialization', () => { + beforeEach(() => { + initTimeTrackingComponent({ + timeEstimate: 100000, + timeSpent: 5000, + timeEstimateHumanReadable: '2h 46m', + timeSpentHumanReadable: '1h 23m', + }); + }); + + it('should return something defined', () => { + expect(vm).toBeDefined(); + }); + + it('should correctly set timeEstimate', done => { + Vue.nextTick(() => { + expect(vm.timeEstimate).toBe(initialData.time_estimate); + done(); + }); + }); + + it('should correctly set time_spent', done => { + Vue.nextTick(() => { + expect(vm.timeSpent).toBe(initialData.time_spent); + done(); + }); + }); + }); + + describe('Content Display', () => { + describe('Panes', () => { + describe('Comparison pane', () => { + beforeEach(() => { + initTimeTrackingComponent({ + timeEstimate: 100000, + timeSpent: 5000, + timeEstimateHumanReadable: '', + timeSpentHumanReadable: '', + }); + }); + + it('should show the "Comparison" pane when timeEstimate and time_spent are truthy', done => { + Vue.nextTick(() => { + expect(vm.showComparisonState).toBe(true); + const $comparisonPane = vm.$el.querySelector('.time-tracking-comparison-pane'); + expect($comparisonPane).toBeVisible(); + done(); + }); + }); + + describe('Remaining meter', () => { + it('should display the remaining meter with the correct width', done => { + Vue.nextTick(() => { + const meterWidth = vm.$el.querySelector('.time-tracking-comparison-pane .meter-fill') + .style.width; + const correctWidth = '5%'; + + expect(meterWidth).toBe(correctWidth); + done(); + }); + }); + + it('should display the remaining meter with the correct background color when within estimate', done => { + Vue.nextTick(() => { + const styledMeter = $(vm.$el).find( + '.time-tracking-comparison-pane .within_estimate .meter-fill', + ); + expect(styledMeter.length).toBe(1); + done(); + }); + }); + + it('should display the remaining meter with the correct background color when over estimate', done => { + vm.time_estimate = 100000; + vm.time_spent = 20000000; + Vue.nextTick(() => { + const styledMeter = $(vm.$el).find( + '.time-tracking-comparison-pane .over_estimate .meter-fill', + ); + expect(styledMeter.length).toBe(1); + done(); + }); + }); + }); + }); + + describe('Estimate only pane', () => { + beforeEach(() => { + initTimeTrackingComponent({ + timeEstimate: 100000, + timeSpent: 0, + timeEstimateHumanReadable: '2h 46m', + timeSpentHumanReadable: '', + }); + }); + + it('should display the human readable version of time estimated', done => { + Vue.nextTick(() => { + const estimateText = vm.$el.querySelector('.time-tracking-estimate-only-pane') + .innerText; + const correctText = 'Estimated: 2h 46m'; + + expect(estimateText).toBe(correctText); + done(); + }); + }); + }); + + describe('Spent only pane', () => { + beforeEach(() => { + initTimeTrackingComponent({ + timeEstimate: 0, + timeSpent: 5000, + timeEstimateHumanReadable: '2h 46m', + timeSpentHumanReadable: '1h 23m', + }); + }); + + it('should display the human readable version of time spent', done => { + Vue.nextTick(() => { + const spentText = vm.$el.querySelector('.time-tracking-spend-only-pane').innerText; + const correctText = 'Spent: 1h 23m'; + + expect(spentText).toBe(correctText); + done(); + }); + }); + }); + + describe('No time tracking pane', () => { + beforeEach(() => { + initTimeTrackingComponent({ + timeEstimate: 0, + timeSpent: 0, + timeEstimateHumanReadable: '', + timeSpentHumanReadable: '', + }); + }); + + it('should only show the "No time tracking" pane when both timeEstimate and time_spent are falsey', done => { + Vue.nextTick(() => { + const $noTrackingPane = vm.$el.querySelector('.time-tracking-no-tracking-pane'); + const noTrackingText = $noTrackingPane.innerText; + const correctText = 'No estimate or time spent'; + + expect(vm.showNoTimeTrackingState).toBe(true); + expect($noTrackingPane).toBeVisible(); + expect(noTrackingText).toBe(correctText); + done(); + }); + }); + }); + + describe('Help pane', () => { + const helpButton = () => vm.$el.querySelector('.help-button'); + const closeHelpButton = () => vm.$el.querySelector('.close-help-button'); + const helpPane = () => vm.$el.querySelector('.time-tracking-help-state'); + + beforeEach(done => { + initTimeTrackingComponent({ timeEstimate: 0, timeSpent: 0 }); + + Vue.nextTick() + .then(done) + .catch(done.fail); + }); + + it('should not show the "Help" pane by default', () => { + expect(vm.showHelpState).toBe(false); + expect(helpPane()).toBeNull(); + }); + + it('should show the "Help" pane when help button is clicked', done => { + helpButton().click(); + + Vue.nextTick() + .then(() => { + expect(vm.showHelpState).toBe(true); + expect(helpPane()).toBeVisible(); + }) + .then(done) + .catch(done.fail); + }); + + it('should not show the "Help" pane when help button is clicked and then closed', done => { + helpButton().click(); + + Vue.nextTick() + .then(() => closeHelpButton().click()) + .then(() => Vue.nextTick()) + .then(() => { + expect(vm.showHelpState).toBe(false); + expect(helpPane()).toBeNull(); + }) + .then(done) + .catch(done.fail); + }); + }); + }); + }); +}); diff --git a/spec/javascripts/sidebar/todo_spec.js b/spec/javascripts/sidebar/todo_spec.js deleted file mode 100644 index a929b804a29..00000000000 --- a/spec/javascripts/sidebar/todo_spec.js +++ /dev/null @@ -1,158 +0,0 @@ -import Vue from 'vue'; - -import SidebarTodos from '~/sidebar/components/todo_toggle/todo.vue'; -import mountComponent from 'spec/helpers/vue_mount_component_helper'; - -const createComponent = ({ - issuableId = 1, - issuableType = 'epic', - isTodo, - isActionActive, - collapsed, -}) => { - const Component = Vue.extend(SidebarTodos); - - return mountComponent(Component, { - issuableId, - issuableType, - isTodo, - isActionActive, - collapsed, - }); -}; - -describe('SidebarTodo', () => { - let vm; - - beforeEach(() => { - vm = createComponent({}); - }); - - afterEach(() => { - vm.$destroy(); - }); - - describe('computed', () => { - describe('buttonClasses', () => { - it('returns todo button classes for when `collapsed` prop is `false`', () => { - expect(vm.buttonClasses).toBe('btn btn-default btn-todo issuable-header-btn float-right'); - }); - - it('returns todo button classes for when `collapsed` prop is `true`', done => { - vm.collapsed = true; - Vue.nextTick() - .then(() => { - expect(vm.buttonClasses).toBe('btn-blank btn-todo sidebar-collapsed-icon dont-change-state'); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('buttonLabel', () => { - it('returns todo button text for marking todo as done when `isTodo` prop is `true`', () => { - expect(vm.buttonLabel).toBe('Mark todo as done'); - }); - - it('returns todo button text for add todo when `isTodo` prop is `false`', done => { - vm.isTodo = false; - Vue.nextTick() - .then(() => { - expect(vm.buttonLabel).toBe('Add todo'); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('collapsedButtonIconClasses', () => { - it('returns collapsed button icon class when `isTodo` prop is `true`', () => { - expect(vm.collapsedButtonIconClasses).toBe('todo-undone'); - }); - - it('returns empty string when `isTodo` prop is `false`', done => { - vm.isTodo = false; - Vue.nextTick() - .then(() => { - expect(vm.collapsedButtonIconClasses).toBe(''); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('collapsedButtonIcon', () => { - it('returns button icon name when `isTodo` prop is `true`', () => { - expect(vm.collapsedButtonIcon).toBe('todo-done'); - }); - - it('returns button icon name when `isTodo` prop is `false`', done => { - vm.isTodo = false; - Vue.nextTick() - .then(() => { - expect(vm.collapsedButtonIcon).toBe('todo-add'); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - - describe('methods', () => { - describe('handleButtonClick', () => { - it('emits `toggleTodo` event on component', () => { - spyOn(vm, '$emit'); - vm.handleButtonClick(); - expect(vm.$emit).toHaveBeenCalledWith('toggleTodo'); - }); - }); - }); - - describe('template', () => { - it('renders component container element', () => { - const dataAttributes = { - issuableId: '1', - issuableType: 'epic', - originalTitle: 'Mark todo as done', - placement: 'left', - container: 'body', - boundary: 'viewport', - }; - expect(vm.$el.nodeName).toBe('BUTTON'); - - const elDataAttrs = vm.$el.dataset; - Object.keys(elDataAttrs).forEach((attr) => { - expect(elDataAttrs[attr]).toBe(dataAttributes[attr]); - }); - }); - - it('renders button label element when `collapsed` prop is `false`', () => { - const buttonLabelEl = vm.$el.querySelector('span.issuable-todo-inner'); - expect(buttonLabelEl).not.toBeNull(); - expect(buttonLabelEl.innerText.trim()).toBe('Mark todo as done'); - }); - - it('renders button icon when `collapsed` prop is `true`', done => { - vm.collapsed = true; - Vue.nextTick() - .then(() => { - const buttonIconEl = vm.$el.querySelector('svg'); - expect(buttonIconEl).not.toBeNull(); - expect(buttonIconEl.querySelector('use').getAttribute('xlink:href')).toContain('todo-done'); - }) - .then(done) - .catch(done.fail); - }); - - it('renders loading icon when `isActionActive` prop is true', done => { - vm.isActionActive = true; - Vue.nextTick() - .then(() => { - const loadingEl = vm.$el.querySelector('span.loading-container'); - expect(loadingEl).not.toBeNull(); - }) - .then(done) - .catch(done.fail); - }); - }); -}); diff --git a/spec/javascripts/smart_interval_spec.js b/spec/javascripts/smart_interval_spec.js index 60153672214..d9b6dd1d487 100644 --- a/spec/javascripts/smart_interval_spec.js +++ b/spec/javascripts/smart_interval_spec.js @@ -1,12 +1,12 @@ import $ from 'jquery'; import _ from 'underscore'; import SmartInterval from '~/smart_interval'; +import waitForPromises from 'spec/helpers/wait_for_promises'; describe('SmartInterval', function () { const DEFAULT_MAX_INTERVAL = 100; const DEFAULT_STARTING_INTERVAL = 5; const DEFAULT_SHORT_TIMEOUT = 75; - const DEFAULT_LONG_TIMEOUT = 1000; const DEFAULT_INCREMENT_FACTOR = 2; function createDefaultSmartInterval(config) { @@ -27,52 +27,65 @@ describe('SmartInterval', function () { return new SmartInterval(defaultParams); } + beforeEach(() => { + jasmine.clock().install(); + }); + + afterEach(() => { + jasmine.clock().uninstall(); + }); + describe('Increment Interval', function () { - beforeEach(function () { - this.smartInterval = createDefaultSmartInterval(); - }); + it('should increment the interval delay', (done) => { + const smartInterval = createDefaultSmartInterval(); - it('should increment the interval delay', function (done) { - const interval = this.smartInterval; - setTimeout(() => { - const intervalConfig = this.smartInterval.cfg; - const iterationCount = 4; - const maxIntervalAfterIterations = intervalConfig.startingInterval * - (intervalConfig.incrementByFactorOf ** (iterationCount - 1)); // 40 - const currentInterval = interval.getCurrentInterval(); - - // Provide some flexibility for performance of testing environment - expect(currentInterval).toBeGreaterThan(intervalConfig.startingInterval); - expect(currentInterval <= maxIntervalAfterIterations).toBeTruthy(); - - done(); - }, DEFAULT_SHORT_TIMEOUT); // 4 iterations, increment by 2x = (5 + 10 + 20 + 40) + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); + + waitForPromises() + .then(() => { + const intervalConfig = smartInterval.cfg; + const iterationCount = 4; + const maxIntervalAfterIterations = intervalConfig.startingInterval * + (intervalConfig.incrementByFactorOf ** iterationCount); + const currentInterval = smartInterval.getCurrentInterval(); + + // Provide some flexibility for performance of testing environment + expect(currentInterval).toBeGreaterThan(intervalConfig.startingInterval); + expect(currentInterval).toBeLessThanOrEqual(maxIntervalAfterIterations); + }) + .then(done) + .catch(done.fail); }); - it('should not increment past maxInterval', function (done) { - const interval = this.smartInterval; + it('should not increment past maxInterval', (done) => { + const smartInterval = createDefaultSmartInterval({ maxInterval: DEFAULT_STARTING_INTERVAL }); - setTimeout(() => { - const currentInterval = interval.getCurrentInterval(); - expect(currentInterval).toBe(interval.cfg.maxInterval); + jasmine.clock().tick(DEFAULT_STARTING_INTERVAL); + jasmine.clock().tick(DEFAULT_STARTING_INTERVAL * DEFAULT_INCREMENT_FACTOR); - done(); - }, DEFAULT_LONG_TIMEOUT); + waitForPromises() + .then(() => { + const currentInterval = smartInterval.getCurrentInterval(); + expect(currentInterval).toBe(smartInterval.cfg.maxInterval); + }) + .then(done) + .catch(done.fail); }); - it('does not increment while waiting for callback', function () { - jasmine.clock().install(); - + it('does not increment while waiting for callback', done => { const smartInterval = createDefaultSmartInterval({ callback: () => new Promise($.noop), }); jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); - const oneInterval = smartInterval.cfg.startingInterval * DEFAULT_INCREMENT_FACTOR; - expect(smartInterval.getCurrentInterval()).toEqual(oneInterval); - - jasmine.clock().uninstall(); + waitForPromises() + .then(() => { + const oneInterval = smartInterval.cfg.startingInterval * DEFAULT_INCREMENT_FACTOR; + expect(smartInterval.getCurrentInterval()).toEqual(oneInterval); + }) + .then(done) + .catch(done.fail); }); }); @@ -84,34 +97,39 @@ describe('SmartInterval', function () { it('should cancel an interval', function (done) { const interval = this.smartInterval; - setTimeout(() => { - interval.cancel(); + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); - const { intervalId } = interval.state; - const currentInterval = interval.getCurrentInterval(); - const intervalLowerLimit = interval.cfg.startingInterval; + interval.cancel(); - expect(intervalId).toBeUndefined(); - expect(currentInterval).toBe(intervalLowerLimit); + waitForPromises() + .then(() => { + const { intervalId } = interval.state; + const currentInterval = interval.getCurrentInterval(); + const intervalLowerLimit = interval.cfg.startingInterval; - done(); - }, DEFAULT_SHORT_TIMEOUT); + expect(intervalId).toBeUndefined(); + expect(currentInterval).toBe(intervalLowerLimit); + }) + .then(done) + .catch(done.fail); }); it('should resume an interval', function (done) { const interval = this.smartInterval; - setTimeout(() => { - interval.cancel(); - - interval.resume(); + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); - const { intervalId } = interval.state; + interval.cancel(); - expect(intervalId).toBeTruthy(); + interval.resume(); - done(); - }, DEFAULT_SHORT_TIMEOUT); + waitForPromises() + .then(() => { + const { intervalId } = interval.state; + expect(intervalId).toBeTruthy(); + }) + .then(done) + .catch(done.fail); }); }); @@ -126,64 +144,79 @@ describe('SmartInterval', function () { it('should pause when page is not visible', function (done) { const interval = this.smartInterval; - setTimeout(() => { - expect(interval.state.intervalId).toBeTruthy(); + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); + + waitForPromises() + .then(() => { + expect(interval.state.intervalId).toBeTruthy(); - // simulates triggering of visibilitychange event - interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } }); + // simulates triggering of visibilitychange event + interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } }); - expect(interval.state.intervalId).toBeUndefined(); - done(); - }, DEFAULT_SHORT_TIMEOUT); + expect(interval.state.intervalId).toBeUndefined(); + }) + .then(done) + .catch(done.fail); }); - it('should change to the hidden interval when page is not visible', function (done) { + it('should change to the hidden interval when page is not visible', done => { const HIDDEN_INTERVAL = 1500; const interval = createDefaultSmartInterval({ hiddenInterval: HIDDEN_INTERVAL }); - setTimeout(() => { - expect(interval.state.intervalId).toBeTruthy(); - expect(interval.getCurrentInterval() >= DEFAULT_STARTING_INTERVAL && - interval.getCurrentInterval() <= DEFAULT_MAX_INTERVAL).toBeTruthy(); + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); + + waitForPromises() + .then(() => { + expect(interval.state.intervalId).toBeTruthy(); + expect(interval.getCurrentInterval() >= DEFAULT_STARTING_INTERVAL && + interval.getCurrentInterval() <= DEFAULT_MAX_INTERVAL).toBeTruthy(); - // simulates triggering of visibilitychange event - interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } }); + // simulates triggering of visibilitychange event + interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } }); - expect(interval.state.intervalId).toBeTruthy(); - expect(interval.getCurrentInterval()).toBe(HIDDEN_INTERVAL); - done(); - }, DEFAULT_SHORT_TIMEOUT); + expect(interval.state.intervalId).toBeTruthy(); + expect(interval.getCurrentInterval()).toBe(HIDDEN_INTERVAL); + }) + .then(done) + .catch(done.fail); }); it('should resume when page is becomes visible at the previous interval', function (done) { const interval = this.smartInterval; - setTimeout(() => { - expect(interval.state.intervalId).toBeTruthy(); + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); - // simulates triggering of visibilitychange event - interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } }); + waitForPromises() + .then(() => { + expect(interval.state.intervalId).toBeTruthy(); - expect(interval.state.intervalId).toBeUndefined(); + // simulates triggering of visibilitychange event + interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } }); - // simulates triggering of visibilitychange event - interval.handleVisibilityChange({ target: { visibilityState: 'visible' } }); + expect(interval.state.intervalId).toBeUndefined(); - expect(interval.state.intervalId).toBeTruthy(); + // simulates triggering of visibilitychange event + interval.handleVisibilityChange({ target: { visibilityState: 'visible' } }); - done(); - }, DEFAULT_SHORT_TIMEOUT); + expect(interval.state.intervalId).toBeTruthy(); + }) + .then(done) + .catch(done.fail); }); it('should cancel on page unload', function (done) { const interval = this.smartInterval; - setTimeout(() => { - $(document).triggerHandler('beforeunload'); - expect(interval.state.intervalId).toBeUndefined(); - expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval); - done(); - }, DEFAULT_SHORT_TIMEOUT); + jasmine.clock().tick(DEFAULT_SHORT_TIMEOUT); + + waitForPromises() + .then(() => { + $(document).triggerHandler('beforeunload'); + expect(interval.state.intervalId).toBeUndefined(); + expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval); + }) + .then(done) + .catch(done.fail); }); it('should execute callback before first interval', function () { diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb index 9a2e521fdcf..919825a6102 100644 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/redactor_filter_spec.rb @@ -46,7 +46,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows permitted Project references' do user = create(:user) project = create(:project) - project.add_master(user) + project.add_maintainer(user) link = reference_link(project: project.id, reference_type: 'test') doc = filter(link, current_user: user) diff --git a/spec/lib/gitlab/background_migration/delete_diff_files_spec.rb b/spec/lib/gitlab/background_migration/delete_diff_files_spec.rb index 1b3df7b20d4..64c994a268f 100644 --- a/spec/lib/gitlab/background_migration/delete_diff_files_spec.rb +++ b/spec/lib/gitlab/background_migration/delete_diff_files_spec.rb @@ -1,31 +1,35 @@ require 'spec_helper' -describe Gitlab::BackgroundMigration::DeleteDiffFiles, :migration, schema: 20180626125654 do +describe Gitlab::BackgroundMigration::DeleteDiffFiles, :migration, schema: 20180619121030 do describe '#perform' do context 'when diff files can be deleted' do let(:merge_request) { create(:merge_request, :merged) } - let(:merge_request_diff) do + let!(:merge_request_diff) do merge_request.create_merge_request_diff merge_request.merge_request_diffs.first end + let(:perform) do + described_class.new.perform(MergeRequestDiff.pluck(:id)) + end + it 'deletes all merge request diff files' do - expect { described_class.new.perform(merge_request_diff.id) } + expect { perform } .to change { merge_request_diff.merge_request_diff_files.count } .from(20).to(0) end it 'updates state to without_files' do - expect { described_class.new.perform(merge_request_diff.id) } + expect { perform } .to change { merge_request_diff.reload.state } .from('collected').to('without_files') end it 'rollsback if something goes wrong' do - expect(MergeRequestDiffFile).to receive_message_chain(:where, :delete_all) + expect(described_class::MergeRequestDiffFile).to receive_message_chain(:where, :delete_all) .and_raise - expect { described_class.new.perform(merge_request_diff.id) } + expect { perform } .to raise_error merge_request_diff.reload @@ -35,35 +39,35 @@ describe Gitlab::BackgroundMigration::DeleteDiffFiles, :migration, schema: 20180 end end - it 'deletes no merge request diff files when MR is not merged' do - merge_request = create(:merge_request, :opened) - merge_request.create_merge_request_diff - merge_request_diff = merge_request.merge_request_diffs.first - - expect { described_class.new.perform(merge_request_diff.id) } - .not_to change { merge_request_diff.merge_request_diff_files.count } - .from(20) - end - - it 'deletes no merge request diff files when diff is marked as "without_files"' do + it 'reschedules itself when should_wait_deadtuple_vacuum' do merge_request = create(:merge_request, :merged) - merge_request.create_merge_request_diff - merge_request_diff = merge_request.merge_request_diffs.first + first_diff = merge_request.merge_request_diff + second_diff = merge_request.create_merge_request_diff - merge_request_diff.clean! + Sidekiq::Testing.fake! do + worker = described_class.new + allow(worker).to receive(:should_wait_deadtuple_vacuum?) { true } - expect { described_class.new.perform(merge_request_diff.id) } - .not_to change { merge_request_diff.merge_request_diff_files.count } - .from(20) + worker.perform([first_diff.id, second_diff.id]) + + expect(described_class.name.demodulize).to be_scheduled_delayed_migration(5.minutes, [first_diff.id, second_diff.id]) + expect(BackgroundMigrationWorker.jobs.size).to eq(1) + end end + end - it 'deletes no merge request diff files when diff is the latest' do - merge_request = create(:merge_request, :merged) - merge_request_diff = merge_request.merge_request_diff + describe '#should_wait_deadtuple_vacuum?' do + it 'returns true when hitting merge_request_diff_files hits DEAD_TUPLES_THRESHOLD', :postgresql do + worker = described_class.new + threshold_query_result = [{ "n_dead_tup" => described_class::DEAD_TUPLES_THRESHOLD.to_s }] + normal_query_result = [{ "n_dead_tup" => '3' }] + + allow(worker) + .to receive(:execute_statement) + .with(/SELECT n_dead_tup */) + .and_return(threshold_query_result, normal_query_result) - expect { described_class.new.perform(merge_request_diff.id) } - .not_to change { merge_request_diff.merge_request_diff_files.count } - .from(20) + expect(worker.should_wait_deadtuple_vacuum?).to be(true) end end end diff --git a/spec/lib/gitlab/background_migration/schedule_diff_files_deletion_spec.rb b/spec/lib/gitlab/background_migration/schedule_diff_files_deletion_spec.rb new file mode 100644 index 00000000000..fb5093b0bd1 --- /dev/null +++ b/spec/lib/gitlab/background_migration/schedule_diff_files_deletion_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::ScheduleDiffFilesDeletion, :migration, schema: 20180619121030 do + describe '#perform' do + let(:merge_request_diffs) { table(:merge_request_diffs) } + let(:merge_requests) { table(:merge_requests) } + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + + before do + stub_const("#{described_class.name}::DIFF_BATCH_SIZE", 3) + + namespaces.create!(id: 1, name: 'gitlab', path: 'gitlab') + projects.create!(id: 1, namespace_id: 1, name: 'gitlab', path: 'gitlab') + + merge_requests.create!(id: 1, target_project_id: 1, source_project_id: 1, target_branch: 'feature', source_branch: 'master', state: 'merged') + + merge_request_diffs.create!(id: 1, merge_request_id: 1, state: 'collected') + merge_request_diffs.create!(id: 2, merge_request_id: 1, state: 'empty') + merge_request_diffs.create!(id: 3, merge_request_id: 1, state: 'without_files') + merge_request_diffs.create!(id: 4, merge_request_id: 1, state: 'collected') + merge_request_diffs.create!(id: 5, merge_request_id: 1, state: 'collected') + merge_request_diffs.create!(id: 6, merge_request_id: 1, state: 'collected') + merge_request_diffs.create!(id: 7, merge_request_id: 1, state: 'collected') + + merge_requests.update(1, latest_merge_request_diff_id: 7) + end + + it 'correctly schedules diff file deletion workers' do + Sidekiq::Testing.fake! do + Timecop.freeze do + described_class.new.perform + + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, [1, 4, 5]) + + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, [6]) + + expect(BackgroundMigrationWorker.jobs.size).to eq(2) + end + end + end + end +end diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb index 1cb8143a9e9..7c04aa27971 100644 --- a/spec/lib/gitlab/checks/change_access_spec.rb +++ b/spec/lib/gitlab/checks/change_access_spec.rb @@ -54,7 +54,7 @@ describe Gitlab::Checks::ChangeAccess do context 'as maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end context 'deletion' do @@ -144,7 +144,7 @@ describe Gitlab::Checks::ChangeAccess do context 'if the user is allowed to delete protected branches' do before do - project.add_master(user) + project.add_maintainer(user) end context 'through the web interface' do diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb index 6a52ae01b2f..e327399d82d 100644 --- a/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/metadata_spec.rb @@ -2,13 +2,21 @@ require 'spec_helper' describe Gitlab::Ci::Build::Artifacts::Metadata do def metadata(path = '', **opts) - described_class.new(metadata_file_path, path, **opts) + described_class.new(metadata_file_stream, path, **opts) end let(:metadata_file_path) do Rails.root + 'spec/fixtures/ci_build_artifacts_metadata.gz' end + let(:metadata_file_stream) do + File.open(metadata_file_path) if metadata_file_path + end + + after do + metadata_file_stream&.close + end + context 'metadata file exists' do describe '#find_entries! empty string' do subject { metadata('').find_entries! } @@ -86,11 +94,21 @@ describe Gitlab::Ci::Build::Artifacts::Metadata do end context 'metadata file does not exist' do - let(:metadata_file_path) { '' } + let(:metadata_file_path) { nil } + + describe '#find_entries!' do + it 'raises error' do + expect { metadata.find_entries! }.to raise_error(described_class::InvalidStreamError, /Invalid stream/) + end + end + end + + context 'metadata file is invalid' do + let(:metadata_file_path) { Rails.root + 'spec/fixtures/ci_build_artifacts.zip' } describe '#find_entries!' do it 'raises error' do - expect { metadata.find_entries! }.to raise_error(Errno::ENOENT) + expect { metadata.find_entries! }.to raise_error(described_class::InvalidStreamError, /not in gzip format/) end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb index a973ccda8de..8ba56d73838 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb @@ -99,9 +99,9 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do end end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it { is_expected.to be_truthy } diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb index e2bb378f663..02f8c4c114b 100644 --- a/spec/lib/gitlab/ci/status/build/play_spec.rb +++ b/spec/lib/gitlab/ci/status/build/play_spec.rb @@ -46,7 +46,7 @@ describe Gitlab::Ci::Status::Build::Play do context 'when user can not push to the branch' do before do build.project.add_developer(user) - create(:protected_branch, :masters_can_push, + create(:protected_branch, :maintainers_can_push, name: build.ref, project: project) end diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb index 6ec35f8da7e..bb2d0a2c75c 100644 --- a/spec/lib/gitlab/ci/status/stage/common_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::Ci::Status::Stage::Common do context 'when user has permission to read pipeline' do before do - project.add_master(user) + project.add_maintainer(user) end it 'has details' do diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 8d4862932b2..3a0688b7cbb 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::ClosingIssueExtractor do before do project.add_developer(project.creator) project.add_developer(project2.creator) - project2.add_master(project.creator) + project2.add_maintainer(project.creator) end describe "#closed_by_message" do @@ -298,7 +298,7 @@ describe Gitlab::ClosingIssueExtractor do context 'with an external issue tracker reference' do it 'extracts the referenced issue' do jira_project = create(:jira_project, name: 'JIRA_EXT1') - jira_project.add_master(jira_project.creator) + jira_project.add_maintainer(jira_project.creator) jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project) closing_issue_extractor = described_class.new(jira_project, jira_project.creator) message = "Resolve #{jira_issue.to_reference}" diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb index 6de4bd3dc7c..f670c7f6c75 100644 --- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb @@ -36,9 +36,9 @@ describe Gitlab::CycleAnalytics::Permissions do end end - context 'user is master' do + context 'user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it 'has permissions to issue stage' do diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 6900c4189b7..034b89a46fa 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -178,77 +178,67 @@ describe Gitlab::Git::Blob, seed_helper: true do end describe '.batch' do - shared_examples 'loading blobs in batch' do - let(:blob_references) do - [ - [SeedRepo::Commit::ID, "files/ruby/popen.rb"], - [SeedRepo::Commit::ID, 'six'] - ] - end + let(:blob_references) do + [ + [SeedRepo::Commit::ID, "files/ruby/popen.rb"], + [SeedRepo::Commit::ID, 'six'] + ] + end - subject { described_class.batch(repository, blob_references) } + subject { described_class.batch(repository, blob_references) } - it { expect(subject.size).to eq(blob_references.size) } + it { expect(subject.size).to eq(blob_references.size) } - context 'first blob' do - let(:blob) { subject[0] } + context 'first blob' do + let(:blob) { subject[0] } - it { expect(blob.id).to eq(SeedRepo::RubyBlob::ID) } - it { expect(blob.name).to eq(SeedRepo::RubyBlob::NAME) } - it { expect(blob.path).to eq("files/ruby/popen.rb") } - it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) } - it { expect(blob.data[0..10]).to eq(SeedRepo::RubyBlob::CONTENT[0..10]) } - it { expect(blob.size).to eq(669) } - it { expect(blob.mode).to eq("100644") } - end + it { expect(blob.id).to eq(SeedRepo::RubyBlob::ID) } + it { expect(blob.name).to eq(SeedRepo::RubyBlob::NAME) } + it { expect(blob.path).to eq("files/ruby/popen.rb") } + it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) } + it { expect(blob.data[0..10]).to eq(SeedRepo::RubyBlob::CONTENT[0..10]) } + it { expect(blob.size).to eq(669) } + it { expect(blob.mode).to eq("100644") } + end - context 'second blob' do - let(:blob) { subject[1] } + context 'second blob' do + let(:blob) { subject[1] } - it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') } - it { expect(blob.data).to eq('') } - it 'does not mark the blob as binary' do - expect(blob).not_to be_binary - end + it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') } + it { expect(blob.data).to eq('') } + it 'does not mark the blob as binary' do + expect(blob).not_to be_binary end + end - context 'limiting' do - subject { described_class.batch(repository, blob_references, blob_size_limit: blob_size_limit) } + context 'limiting' do + subject { described_class.batch(repository, blob_references, blob_size_limit: blob_size_limit) } - context 'positive' do - let(:blob_size_limit) { 10 } + context 'positive' do + let(:blob_size_limit) { 10 } - it { expect(subject.first.data.size).to eq(10) } - end + it { expect(subject.first.data.size).to eq(10) } + end - context 'zero' do - let(:blob_size_limit) { 0 } + context 'zero' do + let(:blob_size_limit) { 0 } - it 'only loads the metadata' do - expect(subject.first.size).not_to be(0) - expect(subject.first.data).to eq('') - end + it 'only loads the metadata' do + expect(subject.first.size).not_to be(0) + expect(subject.first.data).to eq('') end + end - context 'negative' do - let(:blob_size_limit) { -1 } + context 'negative' do + let(:blob_size_limit) { -1 } - it 'ignores MAX_DATA_DISPLAY_SIZE' do - stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', 100) + it 'ignores MAX_DATA_DISPLAY_SIZE' do + stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', 100) - expect(subject.first.data.size).to eq(669) - end + expect(subject.first.data.size).to eq(669) end end end - - context 'when Gitaly list_blobs_by_sha_path feature is enabled' do - it_behaves_like 'loading blobs in batch' - end - - context 'when Gitaly list_blobs_by_sha_path feature is disabled', :disable_gitaly do - it_behaves_like 'loading blobs in batch' - end end describe '.batch_metadata' do @@ -294,58 +284,48 @@ describe Gitlab::Git::Blob, seed_helper: true do ) end - shared_examples 'fetching batch of LFS pointers' do - it 'returns a list of Gitlab::Git::Blob' do - blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id]) - - expect(blobs.count).to eq(1) - expect(blobs).to all( be_a(Gitlab::Git::Blob) ) - expect(blobs).to be_an(Array) - end - - it 'accepts blob IDs as a lazy enumerator' do - blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id].lazy) - - expect(blobs.count).to eq(1) - expect(blobs).to all( be_a(Gitlab::Git::Blob) ) - end + it 'returns a list of Gitlab::Git::Blob' do + blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id]) - it 'handles empty list of IDs gracefully' do - blobs_1 = described_class.batch_lfs_pointers(repository, [].lazy) - blobs_2 = described_class.batch_lfs_pointers(repository, []) + expect(blobs.count).to eq(1) + expect(blobs).to all( be_a(Gitlab::Git::Blob) ) + expect(blobs).to be_an(Array) + end - expect(blobs_1).to eq([]) - expect(blobs_2).to eq([]) - end + it 'accepts blob IDs as a lazy enumerator' do + blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id].lazy) - it 'silently ignores tree objects' do - blobs = described_class.batch_lfs_pointers(repository, [tree_object.oid]) + expect(blobs.count).to eq(1) + expect(blobs).to all( be_a(Gitlab::Git::Blob) ) + end - expect(blobs).to eq([]) - end + it 'handles empty list of IDs gracefully' do + blobs_1 = described_class.batch_lfs_pointers(repository, [].lazy) + blobs_2 = described_class.batch_lfs_pointers(repository, []) - it 'silently ignores non lfs objects' do - blobs = described_class.batch_lfs_pointers(repository, [non_lfs_blob.id]) + expect(blobs_1).to eq([]) + expect(blobs_2).to eq([]) + end - expect(blobs).to eq([]) - end + it 'silently ignores tree objects' do + blobs = described_class.batch_lfs_pointers(repository, [tree_object.oid]) - it 'avoids loading large blobs into memory' do - # This line could call `lookup` on `repository`, so do here before mocking. - non_lfs_blob_id = non_lfs_blob.id + expect(blobs).to eq([]) + end - expect(repository).not_to receive(:lookup) + it 'silently ignores non lfs objects' do + blobs = described_class.batch_lfs_pointers(repository, [non_lfs_blob.id]) - described_class.batch_lfs_pointers(repository, [non_lfs_blob_id]) - end + expect(blobs).to eq([]) end - context 'when Gitaly batch_lfs_pointers is enabled' do - it_behaves_like 'fetching batch of LFS pointers' - end + it 'avoids loading large blobs into memory' do + # This line could call `lookup` on `repository`, so do here before mocking. + non_lfs_blob_id = non_lfs_blob.id + + expect(repository).not_to receive(:lookup) - context 'when Gitaly batch_lfs_pointers is disabled', :disable_gitaly do - it_behaves_like 'fetching batch of LFS pointers' + described_class.batch_lfs_pointers(repository, [non_lfs_blob_id]) end end diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb index ec1a684cfbc..a8c5627e678 100644 --- a/spec/lib/gitlab/git/branch_spec.rb +++ b/spec/lib/gitlab/git/branch_spec.rb @@ -2,6 +2,11 @@ require "spec_helper" describe Gitlab::Git::Branch, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } + let(:rugged) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged + end + end subject { repository.branches } @@ -124,6 +129,7 @@ describe Gitlab::Git::Branch, seed_helper: true do it { expect(repository.branches.size).to eq(SeedRepo::Repo::BRANCHES.size) } def create_commit - repository.create_commit(params.merge(committer: committer.merge(time: Time.now))) + params[:message].delete!("\r") + Rugged::Commit.create(rugged, params.merge(committer: committer.merge(time: Time.now))) end end diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb index 3bb0b5be15b..7c3d2af819b 100644 --- a/spec/lib/gitlab/git/diff_spec.rb +++ b/spec/lib/gitlab/git/diff_spec.rb @@ -27,6 +27,7 @@ EOT too_large: false } + # TODO use a Gitaly diff object instead @rugged_diff = Gitlab::GitalyClient::StorageSettings.allow_disk_access do repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths: [".gitmodules"]).patches.first @@ -266,8 +267,12 @@ EOT describe '#submodule?' do before do - commit = repository.lookup('5937ac0a7beb003549fc5fd26fc247adbce4a52e') - @diffs = commit.parents[0].diff(commit).patches + # TODO use a Gitaly diff object instead + rugged_commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.lookup('5937ac0a7beb003549fc5fd26fc247adbce4a52e') + end + + @diffs = rugged_commit.parents[0].diff(rugged_commit).patches end it { expect(described_class.new(@diffs[0]).submodule?).to eq(false) } diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index e6268a05d44..f155ebc9d1a 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -611,21 +611,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe "#remove_remote" do - before(:all) do - @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') - @repo.remove_remote("expendable") - end - - it "should remove the remote" do - expect(@repo.rugged.remotes).not_to include("expendable") - end - - after(:all) do - ensure_seeds - end - end - describe "#remote_update" do before(:all) do @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') @@ -633,7 +618,9 @@ describe Gitlab::Git::Repository, seed_helper: true do end it "should add the remote" do - expect(@repo.rugged.remotes["expendable"].url).to( + rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access { @repo.rugged } + + expect(rugged.remotes["expendable"].url).to( eq(TEST_NORMAL_REPO_PATH) ) end @@ -1157,6 +1144,13 @@ describe Gitlab::Git::Repository, seed_helper: true do @repo.rugged.config['core.autocrlf'] = true end + around do |example| + # OK because autocrlf is only used in gitaly-ruby + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + it 'return the value of the autocrlf option' do expect(@repo.autocrlf).to be(true) end @@ -1172,6 +1166,13 @@ describe Gitlab::Git::Repository, seed_helper: true do @repo.rugged.config['core.autocrlf'] = false end + around do |example| + # OK because autocrlf= is only used in gitaly-ruby + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + it 'should set the autocrlf option to the provided option' do @repo.autocrlf = :input @@ -1716,59 +1717,51 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe '#fetch_source_branch!' do - shared_examples '#fetch_source_branch!' do - let(:local_ref) { 'refs/merge-requests/1/head' } - let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } - let(:source_repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } - - after do - ensure_seeds - end + let(:local_ref) { 'refs/merge-requests/1/head' } + let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } + let(:source_repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') } - context 'when the branch exists' do - context 'when the commit does not exist locally' do - let(:source_branch) { 'new-branch-for-fetch-source-branch' } - let(:source_rugged) { Gitlab::GitalyClient::StorageSettings.allow_disk_access { source_repository.rugged } } - let(:new_oid) { new_commit_edit_old_file(source_rugged).oid } + after do + ensure_seeds + end - before do - source_rugged.branches.create(source_branch, new_oid) - end + context 'when the branch exists' do + context 'when the commit does not exist locally' do + let(:source_branch) { 'new-branch-for-fetch-source-branch' } + let(:source_rugged) { Gitlab::GitalyClient::StorageSettings.allow_disk_access { source_repository.rugged } } + let(:new_oid) { new_commit_edit_old_file(source_rugged).oid } - it 'writes the ref' do - expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(true) - expect(repository.commit(local_ref).sha).to eq(new_oid) - end + before do + source_rugged.branches.create(source_branch, new_oid) end - context 'when the commit exists locally' do - let(:source_branch) { 'master' } - let(:expected_oid) { SeedRepo::LastCommit::ID } - - it 'writes the ref' do - # Sanity check: the commit should already exist - expect(repository.commit(expected_oid)).not_to be_nil - - expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(true) - expect(repository.commit(local_ref).sha).to eq(expected_oid) - end + it 'writes the ref' do + expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(true) + expect(repository.commit(local_ref).sha).to eq(new_oid) end end - context 'when the branch does not exist' do - let(:source_branch) { 'definitely-not-master' } + context 'when the commit exists locally' do + let(:source_branch) { 'master' } + let(:expected_oid) { SeedRepo::LastCommit::ID } + + it 'writes the ref' do + # Sanity check: the commit should already exist + expect(repository.commit(expected_oid)).not_to be_nil - it 'does not write the ref' do - expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(false) - expect(repository.commit(local_ref)).to be_nil + expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(true) + expect(repository.commit(local_ref).sha).to eq(expected_oid) end end end - it_behaves_like '#fetch_source_branch!' + context 'when the branch does not exist' do + let(:source_branch) { 'definitely-not-master' } - context 'without gitaly', :skip_gitaly_mock do - it_behaves_like '#fetch_source_branch!' + it 'does not write the ref' do + expect(repository.fetch_source_branch!(source_repository, source_branch, local_ref)).to eq(false) + expect(repository.commit(local_ref)).to be_nil + end end end @@ -2050,54 +2043,61 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:repository) do Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') end + let(:rugged) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.rugged } + end let(:remote_name) { 'my-remote' } + let(:url) { 'http://my-repo.git' } after do ensure_seeds end describe '#add_remote' do - let(:url) { 'http://my-repo.git' } let(:mirror_refmap) { '+refs/*:refs/*' } - it 'creates a new remote via Gitaly' do - expect_any_instance_of(Gitlab::GitalyClient::RemoteService) - .to receive(:add_remote).with(remote_name, url, mirror_refmap) + shared_examples 'add_remote' do + it 'added the remote' do + begin + rugged.remotes.delete(remote_name) + rescue Rugged::ConfigError + end + + repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) - repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) + expect(rugged.remotes[remote_name]).not_to be_nil + expect(rugged.config["remote.#{remote_name}.mirror"]).to eq('true') + expect(rugged.config["remote.#{remote_name}.prune"]).to eq('true') + expect(rugged.config["remote.#{remote_name}.fetch"]).to eq(mirror_refmap) + end end - context 'with Gitaly disabled', :skip_gitaly_mock do - it 'creates a new remote via Rugged' do - expect_any_instance_of(Rugged::RemoteCollection).to receive(:create) - .with(remote_name, url) - expect_any_instance_of(Rugged::Config).to receive(:[]=) - .with("remote.#{remote_name}.mirror", true) - expect_any_instance_of(Rugged::Config).to receive(:[]=) - .with("remote.#{remote_name}.prune", true) - expect_any_instance_of(Rugged::Config).to receive(:[]=) - .with("remote.#{remote_name}.fetch", mirror_refmap) + context 'using Gitaly' do + it_behaves_like 'add_remote' + end - repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) - end + context 'with Gitaly disabled', :disable_gitaly do + it_behaves_like 'add_remote' end end describe '#remove_remote' do - it 'removes the remote via Gitaly' do - expect_any_instance_of(Gitlab::GitalyClient::RemoteService) - .to receive(:remove_remote).with(remote_name) + shared_examples 'remove_remote' do + it 'removes the remote' do + rugged.remotes.create(remote_name, url) - repository.remove_remote(remote_name) + repository.remove_remote(remote_name) + + expect(rugged.remotes[remote_name]).to be_nil + end end - context 'with Gitaly disabled', :skip_gitaly_mock do - it 'removes the remote via Rugged' do - expect_any_instance_of(Rugged::RemoteCollection).to receive(:delete) - .with(remote_name) + context 'using Gitaly' do + it_behaves_like 'remove_remote' + end - repository.remove_remote(remote_name) - end + context 'with Gitaly disabled', :disable_gitaly do + it_behaves_like 'remove_remote' end end end @@ -2289,20 +2289,25 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:worktree_path) { File.join(repository_path, 'worktrees', 'delete-me') } it 'cleans up the files' do - repository.with_worktree(worktree_path, 'master', env: ENV) do - FileUtils.touch(worktree_path, mtime: Time.now - 8.hours) - # git rev-list --all will fail in git 2.16 if HEAD is pointing to a non-existent object, - # but the HEAD must be 40 characters long or git will ignore it. - File.write(File.join(worktree_path, 'HEAD'), Gitlab::Git::BLANK_SHA) + create_worktree = %W[git -C #{repository_path} worktree add --detach #{worktree_path} master] + raise 'preparation failed' unless system(*create_worktree, err: '/dev/null') - # git 2.16 fails with "fatal: bad object HEAD" - expect { repository.rev_list(including: :all) }.to raise_error(Gitlab::Git::Repository::GitError) + FileUtils.touch(worktree_path, mtime: Time.now - 8.hours) + # git rev-list --all will fail in git 2.16 if HEAD is pointing to a non-existent object, + # but the HEAD must be 40 characters long or git will ignore it. + File.write(File.join(worktree_path, 'HEAD'), Gitlab::Git::BLANK_SHA) - repository.clean_stale_repository_files + # git 2.16 fails with "fatal: bad object HEAD" + expect(rev_list_all).to be false - expect { repository.rev_list(including: :all) }.not_to raise_error - expect(File.exist?(worktree_path)).to be_falsey - end + repository.clean_stale_repository_files + + expect(rev_list_all).to be true + expect(File.exist?(worktree_path)).to be_falsey + end + + def rev_list_all + system(*%W[git -C #{repository_path} rev-list --all], out: '/dev/null', err: '/dev/null') end it 'increments a counter upon an error' do diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index b752c3e8341..d9d405e1ccc 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -32,65 +32,4 @@ describe Gitlab::Git::RevList do expect(rev_list.new_refs).to eq(%w[sha1 sha2]) end end - - context '#new_objects' do - it 'fetches list of newly pushed objects using rev-list' do - stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2") - - expect { |b| rev_list.new_objects(&b) }.to yield_with_args(%w[sha1 sha2]) - end - - it 'can skip pathless objects' do - stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2 path/to/file") - - expect { |b| rev_list.new_objects(require_path: true, &b) }.to yield_with_args(%w[sha2]) - end - - it 'can handle non utf-8 paths' do - non_utf_char = [0x89].pack("c*").force_encoding("UTF-8") - stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha2 πå†h/†ø/ƒîlé#{non_utf_char}\nsha1") - - rev_list.new_objects(require_path: true) do |object_ids| - expect(object_ids.force).to eq(%w[sha2]) - end - end - - it 'can yield a lazy enumerator' do - stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2") - - rev_list.new_objects do |object_ids| - expect(object_ids).to be_a Enumerator::Lazy - end - end - - it 'returns the result of the block when given' do - stub_popen_rev_list('newrev', '--not', '--all', '--objects', output: "sha1\nsha2") - - objects = rev_list.new_objects do |object_ids| - object_ids.first - end - - expect(objects).to eq 'sha1' - end - - it 'can accept list of references to exclude' do - stub_popen_rev_list('newrev', '--not', 'master', '--objects', output: "sha1\nsha2") - - expect { |b| rev_list.new_objects(not_in: ['master'], &b) }.to yield_with_args(%w[sha1 sha2]) - end - - it 'handles empty list of references to exclude as listing all known objects' do - stub_popen_rev_list('newrev', '--objects', output: "sha1\nsha2") - - expect { |b| rev_list.new_objects(not_in: [], &b) }.to yield_with_args(%w[sha1 sha2]) - end - end - - context '#all_objects' do - it 'fetches list of all pushed objects using rev-list' do - stub_popen_rev_list('--all', '--objects', output: "sha1\nsha2") - - expect { |b| rev_list.all_objects(&b) }.to yield_with_args(%w[sha1 sha2]) - end - end end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index ff32025253a..dbd64c4bec0 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -13,14 +13,6 @@ describe Gitlab::GitAccess do let(:authentication_abilities) { %i[read_project download_code push_code] } let(:redirected_path) { nil } let(:auth_result_type) { nil } - - let(:access) do - described_class.new(actor, project, - protocol, authentication_abilities: authentication_abilities, - namespace_path: namespace_path, project_path: project_path, - redirected_path: redirected_path, auth_result_type: auth_result_type) - end - let(:changes) { '_any' } let(:push_access_check) { access.check('git-receive-pack', changes) } let(:pull_access_check) { access.check('git-upload-pack', changes) } @@ -48,7 +40,7 @@ describe Gitlab::GitAccess do before do disable_protocol('http') - project.add_master(user) + project.add_maintainer(user) end it 'blocks http push and pull' do @@ -113,7 +105,7 @@ describe Gitlab::GitAccess do context 'when actor is a User' do context 'when the User can read the project' do before do - project.add_master(user) + project.add_maintainer(user) end it 'allows push and pull access' do @@ -254,7 +246,7 @@ describe Gitlab::GitAccess do shared_examples '#check with a key that is not valid' do before do - project.add_master(user) + project.add_maintainer(user) end context 'key is too small' do @@ -307,7 +299,7 @@ describe Gitlab::GitAccess do describe '#add_project_moved_message!', :clean_gitlab_redis_shared_state do before do - project.add_master(user) + project.add_maintainer(user) end context 'when a redirect was not followed to find the project' do @@ -335,7 +327,7 @@ describe Gitlab::GitAccess do describe '#check_authentication_abilities!' do before do - project.add_master(user) + project.add_maintainer(user) end context 'when download' do @@ -381,7 +373,7 @@ describe Gitlab::GitAccess do describe '#check_command_disabled!' do before do - project.add_master(user) + project.add_maintainer(user) end context 'over http' do @@ -529,8 +521,8 @@ describe Gitlab::GitAccess do end describe '#check_download_access!' do - it 'allows masters to pull' do - project.add_master(user) + it 'allows maintainers to pull' do + project.add_maintainer(user) expect { pull_access_check }.not_to raise_error end @@ -542,7 +534,7 @@ describe Gitlab::GitAccess do end it 'disallows blocked users to pull' do - project.add_master(user) + project.add_maintainer(user) user.block expect { pull_access_check }.to raise_unauthorized('Your account has been blocked.') @@ -724,10 +716,11 @@ describe Gitlab::GitAccess do end describe '#check_push_access!' do + let(:unprotected_branch) { 'unprotected_branch' } + before do merge_into_protected_branch end - let(:unprotected_branch) { 'unprotected_branch' } let(:changes) do { push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow", @@ -741,26 +734,18 @@ describe Gitlab::GitAccess do merge_into_protected_branch: "0b4bc9a #{merge_into_protected_branch} refs/heads/feature" } end - def stub_git_hooks - # Running the `pre-receive` hook is expensive, and not necessary for this test. - allow_any_instance_of(Gitlab::Git::HooksService).to receive(:execute) do |service, &block| - block.call(service) - end - end - def merge_into_protected_branch @protected_branch_merge_commit ||= begin Gitlab::GitalyClient::StorageSettings.allow_disk_access do - stub_git_hooks project.repository.add_branch(user, unprotected_branch, 'feature') - target_branch = project.repository.lookup('feature') + rugged = project.repository.rugged + target_branch = rugged.rev_parse('feature') source_branch = project.repository.create_file( user, 'filename', 'This is the file content', message: 'This is a good commit message', branch_name: unprotected_branch) - rugged = project.repository.rugged author = { email: "email@example.com", time: Time.now, name: "Example Git User" } merge_index = rugged.merge_commits(target_branch, source_branch) @@ -785,7 +770,7 @@ describe Gitlab::GitAccess do aggregate_failures do matrix.each do |action, allowed| - check = -> { access.send(:check_push_access!, changes[action]) } + check = -> { push_changes(changes[action]) } if allowed expect(&check).not_to raise_error, @@ -812,7 +797,7 @@ describe Gitlab::GitAccess do merge_into_protected_branch: true }, - master: { + maintainer: { push_new_branch: true, push_master: true, push_protected_branch: true, @@ -917,7 +902,7 @@ describe Gitlab::GitAccess do 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 }, + maintainer: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false }, admin: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false })) end end @@ -989,7 +974,7 @@ describe Gitlab::GitAccess do let(:project) { create(:project, :repository, :read_only) } it 'denies push access' do - project.add_master(user) + project.add_maintainer(user) expect { push_access_check }.to raise_unauthorized('The repository is temporarily read-only. Please try again later.') end @@ -1119,9 +1104,9 @@ describe Gitlab::GitAccess do it_behaves_like 'access after accepting terms' end - describe 'as a master of the project' do + describe 'as a maintainer of the project' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'access after accepting terms' @@ -1152,6 +1137,17 @@ describe Gitlab::GitAccess do private + def access + described_class.new(actor, project, protocol, + authentication_abilities: authentication_abilities, + namespace_path: namespace_path, project_path: project_path, + redirected_path: redirected_path, auth_result_type: auth_result_type) + end + + def push_changes(changes) + access.check('git-receive-pack', changes) + end + def raise_unauthorized(message) raise_error(Gitlab::GitAccess::UnauthorizedError, message) end diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb index 017facd0f5e..031f57dbc65 100644 --- a/spec/lib/gitlab/google_code_import/importer_spec.rb +++ b/spec/lib/gitlab/google_code_import/importer_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::GoogleCodeImport::Importer do subject { described_class.new(project) } before do - project.add_master(project.creator) + project.add_maintainer(project.creator) project.create_import_data(data: import_data) end diff --git a/spec/lib/gitlab/ci/trace/http_io_spec.rb b/spec/lib/gitlab/http_io_spec.rb index 5474e2f518c..788bddb8f59 100644 --- a/spec/lib/gitlab/ci/trace/http_io_spec.rb +++ b/spec/lib/gitlab/http_io_spec.rb @@ -1,11 +1,14 @@ require 'spec_helper' -describe Gitlab::Ci::Trace::HttpIO do +describe Gitlab::HttpIO do include HttpIOHelpers let(:http_io) { described_class.new(url, size) } - let(:url) { remote_trace_url } - let(:size) { remote_trace_size } + + let(:url) { 'http://object-storage/trace' } + let(:file_path) { expand_fixture_path('trace/sample_trace') } + let(:file_body) { File.read(file_path).force_encoding(Encoding::BINARY) } + let(:size) { File.size(file_path) } describe '#close' do subject { http_io.close } @@ -86,10 +89,10 @@ describe Gitlab::Ci::Trace::HttpIO do describe '#each_line' do subject { http_io.each_line } - let(:string_io) { StringIO.new(remote_trace_body) } + let(:string_io) { StringIO.new(file_body) } before do - stub_remote_trace_206 + stub_remote_url_206(url, file_path) end it 'yields lines' do @@ -99,7 +102,7 @@ describe Gitlab::Ci::Trace::HttpIO do context 'when buckets on GCS' do context 'when BUFFER_SIZE is larger than file size' do before do - stub_remote_trace_200 + stub_remote_url_200(url, file_path) set_larger_buffer_size_than(size) end @@ -117,7 +120,7 @@ describe Gitlab::Ci::Trace::HttpIO do context 'when there are no network issue' do before do - stub_remote_trace_206 + stub_remote_url_206(url, file_path) end context 'when read whole size' do @@ -129,7 +132,7 @@ describe Gitlab::Ci::Trace::HttpIO do end it 'reads a trace' do - is_expected.to eq(remote_trace_body) + is_expected.to eq(file_body) end end @@ -139,7 +142,7 @@ describe Gitlab::Ci::Trace::HttpIO do end it 'reads a trace' do - is_expected.to eq(remote_trace_body) + is_expected.to eq(file_body) end end end @@ -153,7 +156,7 @@ describe Gitlab::Ci::Trace::HttpIO do end it 'reads a trace' do - is_expected.to eq(remote_trace_body[0, length]) + is_expected.to eq(file_body[0, length]) end end @@ -163,7 +166,7 @@ describe Gitlab::Ci::Trace::HttpIO do end it 'reads a trace' do - is_expected.to eq(remote_trace_body[0, length]) + is_expected.to eq(file_body[0, length]) end end end @@ -177,7 +180,7 @@ describe Gitlab::Ci::Trace::HttpIO do end it 'reads a trace' do - is_expected.to eq(remote_trace_body) + is_expected.to eq(file_body) end end @@ -187,7 +190,7 @@ describe Gitlab::Ci::Trace::HttpIO do end it 'reads a trace' do - is_expected.to eq(remote_trace_body) + is_expected.to eq(file_body) end end end @@ -221,11 +224,11 @@ describe Gitlab::Ci::Trace::HttpIO do let(:length) { nil } before do - stub_remote_trace_500 + stub_remote_url_500(url) end it 'reads a trace' do - expect { subject }.to raise_error(Gitlab::Ci::Trace::HttpIO::FailedToGetChunkError) + expect { subject }.to raise_error(Gitlab::HttpIO::FailedToGetChunkError) end end end @@ -233,15 +236,15 @@ describe Gitlab::Ci::Trace::HttpIO do describe '#readline' do subject { http_io.readline } - let(:string_io) { StringIO.new(remote_trace_body) } + let(:string_io) { StringIO.new(file_body) } before do - stub_remote_trace_206 + stub_remote_url_206(url, file_path) end shared_examples 'all line matching' do it 'reads a line' do - (0...remote_trace_body.lines.count).each do + (0...file_body.lines.count).each do expect(http_io.readline).to eq(string_io.readline) end end @@ -251,11 +254,11 @@ describe Gitlab::Ci::Trace::HttpIO do let(:length) { nil } before do - stub_remote_trace_500 + stub_remote_url_500(url) end it 'reads a trace' do - expect { subject }.to raise_error(Gitlab::Ci::Trace::HttpIO::FailedToGetChunkError) + expect { subject }.to raise_error(Gitlab::HttpIO::FailedToGetChunkError) end end diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb index 246f009ad27..67e4c289906 100644 --- a/spec/lib/gitlab/import_export/members_mapper_spec.rb +++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb @@ -111,7 +111,7 @@ describe Gitlab::ImportExport::MembersMapper do end it 'maps the project member if it already exists' do - project.add_master(user2) + project.add_maintainer(user2) expect(members_mapper.map[exported_user_id]).to eq(user2.id) end diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 2b8a11ce8f9..fec8a2af9ab 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver do let!(:project) { setup_project } before do - project.add_master(user) + project.add_maintainer(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD') allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA') @@ -217,8 +217,8 @@ describe Gitlab::ImportExport::ProjectTreeSaver do expect(member_emails).not_to include('group@member.com') end - it 'does not export group members as master' do - Group.first.add_master(user) + it 'does not export group members as maintainer' do + Group.first.add_maintainer(user) expect(member_emails).not_to include('group@member.com') end diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb index 187ec8fcfa2..5a646b4aac8 100644 --- a/spec/lib/gitlab/import_export/repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::RepoSaver do let(:bundler) { described_class.new(project: project, shared: shared) } before do - project.add_master(user) + project.add_maintainer(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) end diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb index 24bc231d5a0..441aa1defe6 100644 --- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::ImportExport::WikiRepoSaver do let!(:project_wiki) { ProjectWiki.new(project, user) } before do - project.add_master(user) + project.add_maintainer(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) project_wiki.wiki project_wiki.create_page("index", "test content") diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb index 10341486512..25827423914 100644 --- a/spec/lib/gitlab/import_sources_spec.rb +++ b/spec/lib/gitlab/import_sources_spec.rb @@ -12,7 +12,8 @@ describe Gitlab::ImportSources do 'FogBugz' => 'fogbugz', 'Repo by URL' => 'git', 'GitLab export' => 'gitlab_project', - 'Gitea' => 'gitea' + 'Gitea' => 'gitea', + 'Manifest file' => 'manifest' } expect(described_class.options).to eq(expected) @@ -31,6 +32,7 @@ describe Gitlab::ImportSources do git gitlab_project gitea + manifest ) expect(described_class.values).to eq(expected) @@ -63,7 +65,8 @@ describe Gitlab::ImportSources do 'fogbugz' => Gitlab::FogbugzImport::Importer, 'git' => nil, 'gitlab_project' => Gitlab::ImportExport::Importer, - 'gitea' => Gitlab::LegacyGithubImport::Importer + 'gitea' => Gitlab::LegacyGithubImport::Importer, + 'manifest' => nil } import_sources.each do |name, klass| @@ -82,7 +85,8 @@ describe Gitlab::ImportSources do 'fogbugz' => 'FogBugz', 'git' => 'Repo by URL', 'gitlab_project' => 'GitLab export', - 'gitea' => 'Gitea' + 'gitea' => 'Gitea', + 'manifest' => 'Manifest file' } import_sources.each do |name, title| diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb index 34b33772578..5c03a2ce7d3 100644 --- a/spec/lib/gitlab/kubernetes_spec.rb +++ b/spec/lib/gitlab/kubernetes_spec.rb @@ -70,4 +70,19 @@ describe Gitlab::Kubernetes do it { is_expected.to eq(YAML.load_file(path)) } end end + + describe '#add_terminal_auth' do + it 'adds authentication parameters to a hash' do + terminal = { original: 'value' } + + add_terminal_auth(terminal, token: 'foo', max_session_time: 0, ca_pem: 'bar') + + expect(terminal).to eq( + original: 'value', + headers: { 'Authorization' => ['Bearer foo'] }, + max_session_time: 0, + ca_pem: 'bar' + ) + end + end end diff --git a/spec/lib/gitlab/manifest_import/manifest_spec.rb b/spec/lib/gitlab/manifest_import/manifest_spec.rb new file mode 100644 index 00000000000..ab305fb2316 --- /dev/null +++ b/spec/lib/gitlab/manifest_import/manifest_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe Gitlab::ManifestImport::Manifest, :postgresql do + let(:file) { File.open(Rails.root.join('spec/fixtures/aosp_manifest.xml')) } + let(:manifest) { described_class.new(file) } + + describe '#valid?' do + context 'valid file' do + it { expect(manifest.valid?).to be true } + end + + context 'missing or invalid attributes' do + let(:file) { Tempfile.new('foo') } + + before do + content = <<~EOS + <manifest> + <remote review="invalid-url" /> + <project name="platform/build"/> + </manifest> + EOS + + file.write(content) + file.rewind + end + + it { expect(manifest.valid?).to be false } + + describe 'errors' do + before do + manifest.valid? + end + + it { expect(manifest.errors).to include('Make sure a <remote> tag is present and is valid.') } + it { expect(manifest.errors).to include('Make sure every <project> tag has name and path attributes.') } + end + end + end + + describe '#projects' do + it { expect(manifest.projects.size).to eq(660) } + it { expect(manifest.projects[0][:name]).to eq('platform/build') } + it { expect(manifest.projects[0][:path]).to eq('build/make') } + it { expect(manifest.projects[0][:url]).to eq('https://android-review.googlesource.com/platform/build') } + end +end diff --git a/spec/lib/gitlab/manifest_import/project_creator_spec.rb b/spec/lib/gitlab/manifest_import/project_creator_spec.rb new file mode 100644 index 00000000000..1d01d437535 --- /dev/null +++ b/spec/lib/gitlab/manifest_import/project_creator_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::ManifestImport::ProjectCreator, :postgresql do + let(:group) { create(:group) } + let(:user) { create(:user) } + let(:repository) do + { + path: 'device/common', + url: 'https://android-review.googlesource.com/device/common' + } + end + + before do + group.add_owner(user) + end + + subject { described_class.new(repository, group, user) } + + describe '#execute' do + it { expect(subject.execute).to be_a(Project) } + it { expect { subject.execute }.to change { Project.count }.by(1) } + it { expect { subject.execute }.to change { Group.count }.by(1) } + + it 'creates project with valid full path and import url' do + subject.execute + + project = Project.last + + expect(project.full_path).to eq(File.join(group.path, 'device/common')) + expect(project.import_url).to eq('https://android-review.googlesource.com/device/common') + end + end +end diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb index b24c9882c0c..7a3a9ab875b 100644 --- a/spec/lib/gitlab/middleware/go_spec.rb +++ b/spec/lib/gitlab/middleware/go_spec.rb @@ -79,7 +79,7 @@ describe Gitlab::Middleware::Go do let(:current_user) { project.creator } before do - project.team.add_master(current_user) + project.team.add_maintainer(current_user) end shared_examples 'authenticated' do diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb index f3cd6961e94..00c62c7bf96 100644 --- a/spec/lib/gitlab/project_authorizations_spec.rb +++ b/spec/lib/gitlab/project_authorizations_spec.rb @@ -41,7 +41,7 @@ describe Gitlab::ProjectAuthorizations do it 'includes the correct access levels' do mapping = map_access_levels(authorizations) - expect(mapping[owned_project.id]).to eq(Gitlab::Access::MASTER) + expect(mapping[owned_project.id]).to eq(Gitlab::Access::MAINTAINER) expect(mapping[other_project.id]).to eq(Gitlab::Access::REPORTER) expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER) end @@ -62,11 +62,11 @@ describe Gitlab::ProjectAuthorizations do end it 'uses the greatest access level when a user is a member of a nested group' do - nested_group.add_master(user) + nested_group.add_maintainer(user) mapping = map_access_levels(authorizations) - expect(mapping[nested_project.id]).to eq(Gitlab::Access::MASTER) + expect(mapping[nested_project.id]).to eq(Gitlab::Access::MAINTAINER) end end end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index 50224bde722..767a3092c73 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -385,7 +385,7 @@ describe Gitlab::ProjectSearchResults do let!(:private_project) { create(:project, :private, :repository, creator: creator, namespace: creator.namespace) } let(:team_master) do user = create(:user, username: 'private-project-master') - private_project.add_master(user) + private_project.add_maintainer(user) user end let(:team_reporter) do diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index c435f988cdd..f8bf896950e 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -403,46 +403,36 @@ describe Gitlab::Shell do end describe '#create_repository' do - shared_examples '#create_repository' do - let(:repository_storage) { 'default' } - let(:repository_storage_path) do - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - Gitlab.config.repositories.storages[repository_storage].legacy_disk_path - end - end - let(:repo_name) { 'project/path' } - let(:created_path) { File.join(repository_storage_path, repo_name + '.git') } - - after do - FileUtils.rm_rf(created_path) + let(:repository_storage) { 'default' } + let(:repository_storage_path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab.config.repositories.storages[repository_storage].legacy_disk_path end + end + let(:repo_name) { 'project/path' } + let(:created_path) { File.join(repository_storage_path, repo_name + '.git') } - it 'creates a repository' do - expect(gitlab_shell.create_repository(repository_storage, repo_name)).to be_truthy - - expect(File.stat(created_path).mode & 0o777).to eq(0o770) + after do + FileUtils.rm_rf(created_path) + end - hooks_path = File.join(created_path, 'hooks') - expect(File.lstat(hooks_path)).to be_symlink - expect(File.realpath(hooks_path)).to eq(gitlab_shell_hooks_path) - end + it 'creates a repository' do + expect(gitlab_shell.create_repository(repository_storage, repo_name)).to be_truthy - it 'returns false when the command fails' do - FileUtils.mkdir_p(File.dirname(created_path)) - # This file will block the creation of the repo's .git directory. That - # should cause #create_repository to fail. - FileUtils.touch(created_path) + expect(File.stat(created_path).mode & 0o777).to eq(0o770) - expect(gitlab_shell.create_repository(repository_storage, repo_name)).to be_falsy - end + hooks_path = File.join(created_path, 'hooks') + expect(File.lstat(hooks_path)).to be_symlink + expect(File.realpath(hooks_path)).to eq(gitlab_shell_hooks_path) end - context 'with gitaly' do - it_behaves_like '#create_repository' - end + it 'returns false when the command fails' do + FileUtils.mkdir_p(File.dirname(created_path)) + # This file will block the creation of the repo's .git directory. That + # should cause #create_repository to fail. + FileUtils.touch(created_path) - context 'without gitaly', :skip_gitaly_mock do - it_behaves_like '#create_repository' + expect(gitlab_shell.create_repository(repository_storage, repo_name)).to be_falsy end end @@ -513,22 +503,12 @@ describe Gitlab::Shell do end end - shared_examples 'fetch_remote' do |gitaly_on| + describe '#fetch_remote' do def fetch_remote(ssh_auth = nil, prune = true) gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth, prune: prune) end - def expect_gitlab_projects(fail = false, options = {}) - expect(gitlab_projects).to receive(:fetch_remote).with( - 'remote-name', - timeout, - options - ).and_return(!fail) - - allow(gitlab_projects).to receive(:output).and_return('error') if fail - end - - def expect_gitaly_call(fail, options = {}) + def expect_call(fail, options = {}) receive_fetch_remote = if fail receive(:fetch_remote).and_raise(GRPC::NotFound) @@ -539,16 +519,6 @@ describe Gitlab::Shell do expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive_fetch_remote end - if gitaly_on - def expect_call(fail, options = {}) - expect_gitaly_call(fail, options) - end - else - def expect_call(fail, options = {}) - expect_gitlab_projects(fail, options) - end - end - def build_ssh_auth(opts = {}) defaults = { ssh_import?: true, @@ -634,14 +604,6 @@ describe Gitlab::Shell do expect(fetch_remote(ssh_auth)).to be_truthy end end - end - - describe '#fetch_remote local', :skip_gitaly_mock do - it_should_behave_like 'fetch_remote', false - end - - describe '#fetch_remote gitaly' do - it_should_behave_like 'fetch_remote', true context 'gitaly call' do let(:remote_name) { 'remote-name' } @@ -683,25 +645,6 @@ describe Gitlab::Shell do end.to raise_error(Gitlab::Shell::Error, "error") end end - - context 'without gitaly', :disable_gitaly do - it 'returns true when the command succeeds' do - expect(gitlab_projects).to receive(:import_project).with(import_url, timeout) { true } - - result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) - - expect(result).to be_truthy - end - - it 'raises an exception when the command fails' do - allow(gitlab_projects).to receive(:output) { 'error' } - expect(gitlab_projects).to receive(:import_project) { false } - - expect do - gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) - end.to raise_error(Gitlab::Shell::Error, "error") - end - end end end diff --git a/spec/lib/gitlab/slash_commands/issue_move_spec.rb b/spec/lib/gitlab/slash_commands/issue_move_spec.rb index d41441c9472..9a990e1fad7 100644 --- a/spec/lib/gitlab/slash_commands/issue_move_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_move_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::SlashCommands::IssueMove, service: true do set(:other_project) { create(:project, namespace: project.namespace) } before do - [project, other_project].each { |prj| prj.add_master(user) } + [project, other_project].each { |prj| prj.add_maintainer(user) } end subject { described_class.new(project, chat_name) } diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb index 8e7df946529..724c76ade6e 100644 --- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::SlashCommands::IssueNew do let(:regex_match) { described_class.match("issue create bird is the word") } before do - project.add_master(user) + project.add_maintainer(user) end subject do diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb index 189e9592f1b..47787307990 100644 --- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb @@ -22,7 +22,7 @@ describe Gitlab::SlashCommands::IssueSearch do context 'the user has access' do before do - project.add_master(user) + project.add_maintainer(user) end it 'returns all results' do diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb index b1db1638237..5c4ba2736ba 100644 --- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::SlashCommands::IssueShow do let(:regex_match) { described_class.match("issue show #{issue.iid}") } before do - project.add_master(user) + project.add_maintainer(user) end subject do diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb index fc8991fd31f..758a9bc5a2b 100644 --- a/spec/lib/gitlab/url_sanitizer_spec.rb +++ b/spec/lib/gitlab/url_sanitizer_spec.rb @@ -92,6 +92,7 @@ describe Gitlab::UrlSanitizer do context 'credentials in URL' do where(:url, :credentials) do 'http://foo:bar@example.com' | { user: 'foo', password: 'bar' } + 'http://foo:bar:baz@example.com' | { user: 'foo', password: 'bar:baz' } 'http://:bar@example.com' | { user: nil, password: 'bar' } 'http://foo:@example.com' | { user: 'foo', password: nil } 'http://foo@example.com' | { user: 'foo', password: nil } diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index 0469d984a40..9da06bb40f4 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -9,8 +9,8 @@ describe Gitlab::UserAccess do describe '#can_push_to_branch?' do describe 'push to none protected branch' do - it 'returns true if user is a master' do - project.add_master(user) + it 'returns true if user is a maintainer' do + project.add_maintainer(user) expect(access.can_push_to_branch?('random_branch')).to be_truthy end @@ -38,8 +38,8 @@ describe Gitlab::UserAccess do expect(access.can_push_to_branch?('master')).to be_truthy end - it 'returns true if user is master' do - empty_project.add_master(user) + it 'returns true if user is maintainer' do + empty_project.add_maintainer(user) expect(project_access.can_push_to_branch?('master')).to be_truthy end @@ -83,8 +83,8 @@ describe Gitlab::UserAccess do expect(access.can_push_to_branch?(branch.name)).to be_truthy end - it 'returns true if user is a master' do - project.add_master(user) + it 'returns true if user is a maintainer' do + project.add_maintainer(user) expect(access.can_push_to_branch?(branch.name)).to be_truthy end @@ -113,8 +113,8 @@ describe Gitlab::UserAccess do @branch = create :protected_branch, :developers_can_push, project: project end - it 'returns true if user is a master' do - project.add_master(user) + it 'returns true if user is a maintainer' do + project.add_maintainer(user) expect(access.can_push_to_branch?(@branch.name)).to be_truthy end @@ -170,8 +170,8 @@ describe Gitlab::UserAccess do @branch = create :protected_branch, :developers_can_merge, project: project end - it 'returns true if user is a master' do - project.add_master(user) + it 'returns true if user is a maintainer' do + project.add_maintainer(user) expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end @@ -192,8 +192,8 @@ describe Gitlab::UserAccess do describe '#can_create_tag?' do describe 'push to none protected tag' do - it 'returns true if user is a master' do - project.add_user(user, :master) + it 'returns true if user is a maintainer' do + project.add_user(user, :maintainer) expect(access.can_create_tag?('random_tag')).to be_truthy end @@ -215,8 +215,8 @@ describe Gitlab::UserAccess do let(:tag) { create(:protected_tag, project: project, name: "test") } let(:not_existing_tag) { create :protected_tag, project: project } - it 'returns true if user is a master' do - project.add_user(user, :master) + it 'returns true if user is a maintainer' do + project.add_user(user, :maintainer) expect(access.can_create_tag?(tag.name)).to be_truthy end @@ -239,8 +239,8 @@ describe Gitlab::UserAccess do @tag = create(:protected_tag, :developers_can_create, project: project) end - it 'returns true if user is a master' do - project.add_user(user, :master) + it 'returns true if user is a maintainer' do + project.add_user(user, :maintainer) expect(access.can_create_tag?(@tag.name)).to be_truthy end @@ -261,8 +261,8 @@ describe Gitlab::UserAccess do describe '#can_delete_branch?' do describe 'delete unprotected branch' do - it 'returns true if user is a master' do - project.add_user(user, :master) + it 'returns true if user is a maintainer' do + project.add_user(user, :maintainer) expect(access.can_delete_branch?('random_branch')).to be_truthy end @@ -283,8 +283,8 @@ describe Gitlab::UserAccess do describe 'delete protected branch' do let(:branch) { create(:protected_branch, project: project, name: "test") } - it 'returns true if user is a master' do - project.add_user(user, :master) + it 'returns true if user is a maintainer' do + project.add_user(user, :maintainer) expect(access.can_delete_branch?(branch.name)).to be_truthy end diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 7802ff1f5f6..23869f3d2da 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -36,22 +36,20 @@ describe Gitlab::Workhorse do allow(described_class).to receive(:git_archive_cache_disabled?).and_return(cache_disabled) end - context 'when Gitaly workhorse_archive feature is enabled' do - it 'sets the header correctly' do - key, command, params = decode_workhorse_header(subject) + it 'sets the header correctly' do + key, command, params = decode_workhorse_header(subject) - expect(key).to eq('Gitlab-Workhorse-Send-Data') - expect(command).to eq('git-archive') - expect(params).to include(gitaly_params) - end + expect(key).to eq('Gitlab-Workhorse-Send-Data') + expect(command).to eq('git-archive') + expect(params).to include(gitaly_params) + end - context 'when archive caching is disabled' do - let(:cache_disabled) { true } + context 'when archive caching is disabled' do + let(:cache_disabled) { true } - it 'tells workhorse not to use the cache' do - _, _, params = decode_workhorse_header(subject) - expect(params).to include({ 'DisableCache' => true }) - end + it 'tells workhorse not to use the cache' do + _, _, params = decode_workhorse_header(subject) + expect(params).to include({ 'DisableCache' => true }) end end @@ -70,34 +68,22 @@ describe Gitlab::Workhorse do let(:diff_refs) { double(base_sha: "base", head_sha: "head") } subject { described_class.send_git_patch(repository, diff_refs) } - context 'when Gitaly workhorse_send_git_patch feature is enabled' do - it 'sets the header correctly' do - key, command, params = decode_workhorse_header(subject) - - expect(key).to eq("Gitlab-Workhorse-Send-Data") - expect(command).to eq("git-format-patch") - expect(params).to eq({ - 'GitalyServer' => { - address: Gitlab::GitalyClient.address(project.repository_storage), - token: Gitlab::GitalyClient.token(project.repository_storage) - }, - 'RawPatchRequest' => Gitaly::RawPatchRequest.new( - repository: repository.gitaly_repository, - left_commit_id: 'base', - right_commit_id: 'head' - ).to_json - }.deep_stringify_keys) - end - end - - context 'when Gitaly workhorse_send_git_patch feature is disabled', :disable_gitaly do - it 'sets the header correctly' do - key, command, params = decode_workhorse_header(subject) + it 'sets the header correctly' do + key, command, params = decode_workhorse_header(subject) - expect(key).to eq("Gitlab-Workhorse-Send-Data") - expect(command).to eq("git-format-patch") - expect(params).to eq("RepoPath" => repository.path_to_repo, "ShaFrom" => "base", "ShaTo" => "head") - end + expect(key).to eq("Gitlab-Workhorse-Send-Data") + expect(command).to eq("git-format-patch") + expect(params).to eq({ + 'GitalyServer' => { + address: Gitlab::GitalyClient.address(project.repository_storage), + token: Gitlab::GitalyClient.token(project.repository_storage) + }, + 'RawPatchRequest' => Gitaly::RawPatchRequest.new( + repository: repository.gitaly_repository, + left_commit_id: 'base', + right_commit_id: 'head' + ).to_json + }.deep_stringify_keys) end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index a9a45367b4a..581132b6672 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -314,6 +314,17 @@ describe Notify do end end + describe 'that are new with a description' do + subject { described_class.new_merge_request_email(merge_request.assignee_id, merge_request.id) } + + it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like "an unsubscribeable thread" + + it 'contains the description' do + is_expected.to have_body_text(merge_request.description) + end + end + describe 'that have been relabeled' do subject { described_class.relabeled_merge_request_email(recipient.id, merge_request.id, %w[foo bar baz], current_user.id) } @@ -541,7 +552,7 @@ describe Notify do describe 'project access requested' do let(:project) do create(:project, :public, :access_requestable) do |project| - project.add_master(project.owner) + project.add_maintainer(project.owner) end end @@ -616,8 +627,8 @@ describe Notify do end describe 'project invitation' do - let(:master) { create(:user).tap { |u| project.add_master(u) } } - let(:project_member) { invite_to_project(project, inviter: master) } + let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } + let(:project_member) { invite_to_project(project, inviter: maintainer) } subject { described_class.member_invited_email('project', project_member.id, project_member.invite_token) } @@ -636,9 +647,9 @@ describe Notify do describe 'project invitation accepted' do let(:invited_user) { create(:user, name: 'invited user') } - let(:master) { create(:user).tap { |u| project.add_master(u) } } + let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } let(:project_member) do - invitee = invite_to_project(project, inviter: master) + invitee = invite_to_project(project, inviter: maintainer) invitee.accept_invite!(invited_user) invitee end @@ -659,14 +670,14 @@ describe Notify do end describe 'project invitation declined' do - let(:master) { create(:user).tap { |u| project.add_master(u) } } + let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } let(:project_member) do - invitee = invite_to_project(project, inviter: master) + invitee = invite_to_project(project, inviter: maintainer) invitee.decline_invite! invitee end - subject { described_class.member_invite_declined_email('project', project.id, project_member.invite_email, master.id) } + subject { described_class.member_invite_declined_email('project', project.id, project_member.invite_email, maintainer.id) } it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' diff --git a/spec/migrations/enqueue_delete_diff_files_workers_spec.rb b/spec/migrations/enqueue_delete_diff_files_workers_spec.rb new file mode 100644 index 00000000000..6bae870920c --- /dev/null +++ b/spec/migrations/enqueue_delete_diff_files_workers_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20180619121030_enqueue_delete_diff_files_workers.rb') + +describe EnqueueDeleteDiffFilesWorkers, :migration, :sidekiq do + it 'correctly schedules diff files deletion schedulers' do + Sidekiq::Testing.fake! do + expect(BackgroundMigrationWorker) + .to receive(:perform_async) + .with(described_class::SCHEDULER) + .and_call_original + + migrate! + + expect(BackgroundMigrationWorker.jobs.size).to eq(1) + end + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 234d2d8aa3a..3c96fe76829 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -2687,4 +2687,58 @@ describe Ci::Build do end end end + + describe '#artifacts_metadata_entry' do + set(:build) { create(:ci_build, project: project) } + let(:path) { 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif' } + + before do + stub_artifacts_object_storage + end + + subject { build.artifacts_metadata_entry(path) } + + context 'when using local storage' do + let!(:metadata) { create(:ci_job_artifact, :metadata, job: build) } + + context 'for existing file' do + it 'does exist' do + is_expected.to be_exists + end + end + + context 'for non-existing file' do + let(:path) { 'invalid-file' } + + it 'does not exist' do + is_expected.not_to be_exists + end + end + end + + context 'when using remote storage' do + include HttpIOHelpers + + let!(:metadata) { create(:ci_job_artifact, :remote_store, :metadata, job: build) } + let(:file_path) { expand_fixture_path('ci_build_artifacts_metadata.gz') } + + before do + stub_remote_url_206(metadata.file.url, file_path) + end + + context 'for existing file' do + it 'does exist' do + is_expected.to be_exists + end + end + + context 'for non-existing file' do + let(:path) { 'invalid-file' } + + it 'does not exist' do + is_expected.not_to be_exists + end + end + end + end end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 1cfd526834c..ec6374f3963 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -549,7 +549,7 @@ describe Issuable do let(:project) { create(:project, namespace: group) } let(:other_project) { create(:project) } let(:owner) { create(:owner) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } @@ -558,7 +558,7 @@ describe Issuable do before do group.add_owner(owner) - project.add_master(master) + project.add_maintainer(maintainer) project.add_reporter(reporter) project.add_guest(guest) project.add_guest(contributor) @@ -570,8 +570,8 @@ describe Issuable do let(:merged_mr_other_project) { create(:merge_request, :merged, author: first_time_contributor, target_project: other_project, source_project: other_project) } context "for merge requests" do - it "is false for MASTER" do - mr = create(:merge_request, author: master, target_project: project, source_project: project) + it "is false for MAINTAINER" do + mr = create(:merge_request, author: maintainer, target_project: project, source_project: project) expect(mr).not_to be_first_contribution end diff --git a/spec/models/concerns/protected_ref_access_spec.rb b/spec/models/concerns/protected_ref_access_spec.rb index a62ca391e25..ce602337647 100644 --- a/spec/models/concerns/protected_ref_access_spec.rb +++ b/spec/models/concerns/protected_ref_access_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ProtectedRefAccess do subject(:protected_ref_access) do - create(:protected_branch, :masters_can_push).push_access_levels.first + create(:protected_branch, :maintainers_can_push).push_access_levels.first end let(:project) { protected_ref_access.project } @@ -14,11 +14,11 @@ describe ProtectedRefAccess do expect(protected_ref_access.check_access(admin)).to be_truthy end - it 'is true for masters' do - master = create(:user) - project.add_master(master) + it 'is true for maintainers' do + maintainer = create(:user) + project.add_maintainer(maintainer) - expect(protected_ref_access.check_access(master)).to be_truthy + expect(protected_ref_access.check_access(maintainer)).to be_truthy end it 'is for developers of the project' do diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index 2f9f63ce7e0..97b046b0f21 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -190,7 +190,7 @@ describe Discussion, ResolvableDiscussion do context "when the signed in user can push to the project" do before do - subject.project.add_master(current_user) + subject.project.add_maintainer(current_user) end it "returns true" do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index aeec485358e..0729eb99e78 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -177,7 +177,7 @@ describe Group do describe 'when the user has access to a group' do before do - group.add_user(user, Gitlab::Access::MASTER) + group.add_user(user, Gitlab::Access::MAINTAINER) end it { is_expected.to eq([group]) } @@ -229,10 +229,10 @@ describe Group do let(:user) { create(:user) } before do - group.add_user(user, GroupMember::MASTER) + group.add_user(user, GroupMember::MAINTAINER) end - it { expect(group.group_members.masters.map(&:user)).to include(user) } + it { expect(group.group_members.maintainers.map(&:user)).to include(user) } end describe '#add_users' do @@ -254,7 +254,7 @@ describe Group do let(:user) { create(:user) } before do - group.add_user(user, GroupMember::MASTER) + group.add_user(user, GroupMember::MAINTAINER) end it "is true if avatar is image" do @@ -274,7 +274,7 @@ describe Group do context 'when avatar file is uploaded' do before do - group.add_master(user) + group.add_maintainer(user) end it 'shows correct avatar url' do @@ -317,7 +317,7 @@ describe Group do end it { expect(group.has_owner?(@members[:owner])).to be_truthy } - it { expect(group.has_owner?(@members[:master])).to be_falsey } + it { expect(group.has_owner?(@members[:maintainer])).to be_falsey } it { expect(group.has_owner?(@members[:developer])).to be_falsey } it { expect(group.has_owner?(@members[:reporter])).to be_falsey } it { expect(group.has_owner?(@members[:guest])).to be_falsey } @@ -325,19 +325,19 @@ describe Group do it { expect(group.has_owner?(nil)).to be_falsey } end - describe '#has_master?' do + describe '#has_maintainer?' do before do @members = setup_group_members(group) - create(:group_member, :invited, :master, group: group) + create(:group_member, :invited, :maintainer, group: group) end - it { expect(group.has_master?(@members[:owner])).to be_falsey } - it { expect(group.has_master?(@members[:master])).to be_truthy } - it { expect(group.has_master?(@members[:developer])).to be_falsey } - it { expect(group.has_master?(@members[:reporter])).to be_falsey } - it { expect(group.has_master?(@members[:guest])).to be_falsey } - it { expect(group.has_master?(@members[:requester])).to be_falsey } - it { expect(group.has_master?(nil)).to be_falsey } + it { expect(group.has_maintainer?(@members[:owner])).to be_falsey } + it { expect(group.has_maintainer?(@members[:maintainer])).to be_truthy } + it { expect(group.has_maintainer?(@members[:developer])).to be_falsey } + it { expect(group.has_maintainer?(@members[:reporter])).to be_falsey } + it { expect(group.has_maintainer?(@members[:guest])).to be_falsey } + it { expect(group.has_maintainer?(@members[:requester])).to be_falsey } + it { expect(group.has_maintainer?(nil)).to be_falsey } end describe '#lfs_enabled?' do @@ -401,7 +401,7 @@ describe Group do def setup_group_members(group) members = { owner: create(:user), - master: create(:user), + maintainer: create(:user), developer: create(:user), reporter: create(:user), guest: create(:user), @@ -409,7 +409,7 @@ describe Group do } group.add_user(members[:owner], GroupMember::OWNER) - group.add_user(members[:master], GroupMember::MASTER) + group.add_user(members[:maintainer], GroupMember::MAINTAINER) group.add_user(members[:developer], GroupMember::DEVELOPER) group.add_user(members[:reporter], GroupMember::REPORTER) group.add_user(members[:guest], GroupMember::GUEST) @@ -439,25 +439,25 @@ describe Group do describe '#members_with_parents', :nested_groups do let!(:group) { create(:group, :nested) } - let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) } + let!(:maintainer) { group.parent.add_user(create(:user), GroupMember::MAINTAINER) } let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) } it 'returns parents members' do expect(group.members_with_parents).to include(developer) - expect(group.members_with_parents).to include(master) + expect(group.members_with_parents).to include(maintainer) end end describe '#direct_and_indirect_members', :nested_groups do let!(:group) { create(:group, :nested) } let!(:sub_group) { create(:group, parent: group) } - let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) } + let!(:maintainer) { group.parent.add_user(create(:user), GroupMember::MAINTAINER) } let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) } let!(:other_developer) { group.add_user(create(:user), GroupMember::DEVELOPER) } it 'returns parents members' do expect(group.direct_and_indirect_members).to include(developer) - expect(group.direct_and_indirect_members).to include(master) + expect(group.direct_and_indirect_members).to include(maintainer) end it 'returns descendant members' do @@ -539,14 +539,14 @@ describe Group do describe '#user_ids_for_project_authorizations' do it 'returns the user IDs for which to refresh authorizations' do - master = create(:user) + maintainer = create(:user) developer = create(:user) - group.add_user(master, GroupMember::MASTER) + group.add_user(maintainer, GroupMember::MAINTAINER) group.add_user(developer, GroupMember::DEVELOPER) expect(group.user_ids_for_project_authorizations) - .to include(master.id, developer.id) + .to include(maintainer.id, developer.id) end end diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 8bc45715dcd..01129df1107 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -63,7 +63,7 @@ describe SystemHook do end it "project_create hook" do - project.add_master(user) + project.add_maintainer(user) expect(WebMock).to have_requested(:post, system_hook.url).with( body: /user_add_to_team/, @@ -72,7 +72,7 @@ describe SystemHook do end it "project_destroy hook" do - project.add_master(user) + project.add_maintainer(user) project.project_members.destroy_all expect(WebMock).to have_requested(:post, system_hook.url).with( @@ -100,7 +100,7 @@ describe SystemHook do end it 'group member create hook' do - group.add_master(user) + group.add_maintainer(user) expect(WebMock).to have_requested(:post, system_hook.url).with( body: /user_add_to_group/, @@ -109,7 +109,7 @@ describe SystemHook do end it 'group member destroy hook' do - group.add_master(user) + group.add_maintainer(user) group.group_members.destroy_all expect(WebMock).to have_requested(:post, system_hook.url).with( diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index e818fbeb9cf..84edfc3ff00 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -669,7 +669,7 @@ describe Issue do context 'when the user is the project owner' do before do - project.add_master(user) + project.add_maintainer(user) end it 'returns true for a regular issue' do diff --git a/spec/models/lfs_file_lock_spec.rb b/spec/models/lfs_file_lock_spec.rb index ce87b01b49c..e74f342d3eb 100644 --- a/spec/models/lfs_file_lock_spec.rb +++ b/spec/models/lfs_file_lock_spec.rb @@ -13,13 +13,13 @@ describe LfsFileLock do describe '#can_be_unlocked_by?' do let(:developer) { create(:user) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } before do project = lfs_file_lock.project project.add_developer(developer) - project.add_master(master) + project.add_maintainer(maintainer) end context "when it's forced" do @@ -29,8 +29,8 @@ describe LfsFileLock do expect(lfs_file_lock.can_be_unlocked_by?(user, true)).to eq(true) end - it 'can be unlocked by a master' do - expect(lfs_file_lock.can_be_unlocked_by?(master, true)).to eq(true) + it 'can be unlocked by a maintainer' do + expect(lfs_file_lock.can_be_unlocked_by?(maintainer, true)).to eq(true) end it "can't be unlocked by other user" do @@ -45,8 +45,8 @@ describe LfsFileLock do expect(lfs_file_lock.can_be_unlocked_by?(user)).to eq(true) end - it "can't be unlocked by a master" do - expect(lfs_file_lock.can_be_unlocked_by?(master)).to eq(false) + it "can't be unlocked by a maintainer" do + expect(lfs_file_lock.can_be_unlocked_by?(maintainer)).to eq(false) end it "can't be unlocked by other user" do diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index c64cdf8f812..fca1b1f90d9 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -62,16 +62,16 @@ describe Member do @owner_user = create(:user).tap { |u| group.add_owner(u) } @owner = group.members.find_by(user_id: @owner_user.id) - @master_user = create(:user).tap { |u| project.add_master(u) } - @master = project.members.find_by(user_id: @master_user.id) + @maintainer_user = create(:user).tap { |u| project.add_maintainer(u) } + @maintainer = project.members.find_by(user_id: @maintainer_user.id) @blocked_user = create(:user).tap do |u| - project.add_master(u) + project.add_maintainer(u) project.add_developer(u) u.block! end - @blocked_master = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::MASTER) + @blocked_maintainer = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::MAINTAINER) @blocked_developer = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::DEVELOPER) @invited_member = create(:project_member, :developer, @@ -95,10 +95,10 @@ describe Member do describe '.access_for_user_ids' do it 'returns the right access levels' do - users = [@owner_user.id, @master_user.id, @blocked_user.id] + users = [@owner_user.id, @maintainer_user.id, @blocked_user.id] expected = { @owner_user.id => Gitlab::Access::OWNER, - @master_user.id => Gitlab::Access::MASTER + @maintainer_user.id => Gitlab::Access::MAINTAINER } expect(described_class.access_for_user_ids(users)).to eq(expected) @@ -106,7 +106,7 @@ describe Member do end describe '.invite' do - it { expect(described_class.invite).not_to include @master } + it { expect(described_class.invite).not_to include @maintainer } it { expect(described_class.invite).to include @invited_member } it { expect(described_class.invite).not_to include @accepted_invite_member } it { expect(described_class.invite).not_to include @requested_member } @@ -114,7 +114,7 @@ describe Member do end describe '.non_invite' do - it { expect(described_class.non_invite).to include @master } + it { expect(described_class.non_invite).to include @maintainer } it { expect(described_class.non_invite).not_to include @invited_member } it { expect(described_class.non_invite).to include @accepted_invite_member } it { expect(described_class.non_invite).to include @requested_member } @@ -122,7 +122,7 @@ describe Member do end describe '.request' do - it { expect(described_class.request).not_to include @master } + it { expect(described_class.request).not_to include @maintainer } it { expect(described_class.request).not_to include @invited_member } it { expect(described_class.request).not_to include @accepted_invite_member } it { expect(described_class.request).to include @requested_member } @@ -130,7 +130,7 @@ describe Member do end describe '.non_request' do - it { expect(described_class.non_request).to include @master } + it { expect(described_class.non_request).to include @maintainer } it { expect(described_class.non_request).to include @invited_member } it { expect(described_class.non_request).to include @accepted_invite_member } it { expect(described_class.non_request).not_to include @requested_member } @@ -141,35 +141,35 @@ describe Member do subject { described_class.developers.to_a } it { is_expected.not_to include @owner } - it { is_expected.not_to include @master } + it { is_expected.not_to include @maintainer } it { is_expected.to include @invited_member } it { is_expected.to include @accepted_invite_member } it { is_expected.not_to include @requested_member } it { is_expected.to include @accepted_request_member } - it { is_expected.not_to include @blocked_master } + it { is_expected.not_to include @blocked_maintainer } it { is_expected.not_to include @blocked_developer } end - describe '.owners_and_masters' do - it { expect(described_class.owners_and_masters).to include @owner } - it { expect(described_class.owners_and_masters).to include @master } - it { expect(described_class.owners_and_masters).not_to include @invited_member } - it { expect(described_class.owners_and_masters).not_to include @accepted_invite_member } - it { expect(described_class.owners_and_masters).not_to include @requested_member } - it { expect(described_class.owners_and_masters).not_to include @accepted_request_member } - it { expect(described_class.owners_and_masters).not_to include @blocked_master } + describe '.owners_and_maintainers' do + it { expect(described_class.owners_and_maintainers).to include @owner } + it { expect(described_class.owners_and_maintainers).to include @maintainer } + it { expect(described_class.owners_and_maintainers).not_to include @invited_member } + it { expect(described_class.owners_and_maintainers).not_to include @accepted_invite_member } + it { expect(described_class.owners_and_maintainers).not_to include @requested_member } + it { expect(described_class.owners_and_maintainers).not_to include @accepted_request_member } + it { expect(described_class.owners_and_maintainers).not_to include @blocked_maintainer } end describe '.has_access' do subject { described_class.has_access.to_a } it { is_expected.to include @owner } - it { is_expected.to include @master } + it { is_expected.to include @maintainer } it { is_expected.to include @invited_member } it { is_expected.to include @accepted_invite_member } it { is_expected.not_to include @requested_member } it { is_expected.to include @accepted_request_member } - it { is_expected.not_to include @blocked_master } + it { is_expected.not_to include @blocked_maintainer } it { is_expected.not_to include @blocked_developer } end end @@ -187,20 +187,20 @@ describe Member do let!(:admin) { create(:admin) } it 'returns a <Source>Member object' do - member = described_class.add_user(source, user, :master) + member = described_class.add_user(source, user, :maintainer) expect(member).to be_a "#{source_type.classify}Member".constantize expect(member).to be_persisted end it 'sets members.created_by to the given current_user' do - member = described_class.add_user(source, user, :master, current_user: admin) + member = described_class.add_user(source, user, :maintainer, current_user: admin) expect(member.created_by).to eq(admin) end it 'sets members.expires_at to the given expires_at' do - member = described_class.add_user(source, user, :master, expires_at: Date.new(2016, 9, 22)) + member = described_class.add_user(source, user, :maintainer, expires_at: Date.new(2016, 9, 22)) expect(member.expires_at).to eq(Date.new(2016, 9, 22)) end @@ -230,7 +230,7 @@ describe Member do it 'adds the user as a member' do expect(source.users).not_to include(user) - described_class.add_user(source, user.id, :master) + described_class.add_user(source, user.id, :maintainer) expect(source.users.reload).to include(user) end @@ -240,7 +240,7 @@ describe Member do it 'adds the user as a member' do expect(source.users).not_to include(user) - described_class.add_user(source, 42, :master) + described_class.add_user(source, 42, :maintainer) expect(source.users.reload).not_to include(user) end @@ -250,7 +250,7 @@ describe Member do it 'adds the user as a member' do expect(source.users).not_to include(user) - described_class.add_user(source, user, :master) + described_class.add_user(source, user, :maintainer) expect(source.users.reload).to include(user) end @@ -265,7 +265,7 @@ describe Member do expect(source.users).not_to include(user) expect(source.requesters.exists?(user_id: user)).to be_truthy - expect { described_class.add_user(source, user, :master) } + expect { described_class.add_user(source, user, :maintainer) } .to raise_error(Gitlab::Access::AccessDeniedError) expect(source.users.reload).not_to include(user) @@ -277,7 +277,7 @@ describe Member do it 'adds the user as a member' do expect(source.users).not_to include(user) - described_class.add_user(source, user.email, :master) + described_class.add_user(source, user.email, :maintainer) expect(source.users.reload).to include(user) end @@ -287,7 +287,7 @@ describe Member do it 'creates an invited member' do expect(source.users).not_to include(user) - described_class.add_user(source, 'user@example.com', :master) + described_class.add_user(source, 'user@example.com', :maintainer) expect(source.members.invite.pluck(:invite_email)).to include('user@example.com') end @@ -298,7 +298,7 @@ describe Member do it 'creates the member' do expect(source.users).not_to include(user) - described_class.add_user(source, user, :master, current_user: admin) + described_class.add_user(source, user, :maintainer, current_user: admin) expect(source.users.reload).to include(user) end @@ -312,7 +312,7 @@ describe Member do expect(source.users).not_to include(user) expect(source.requesters.exists?(user_id: user)).to be_truthy - described_class.add_user(source, user, :master, current_user: admin) + described_class.add_user(source, user, :maintainer, current_user: admin) expect(source.users.reload).to include(user) expect(source.requesters.reload.exists?(user_id: user)).to be_falsy @@ -324,7 +324,7 @@ describe Member do it 'does not create the member' do expect(source.users).not_to include(user) - member = described_class.add_user(source, user, :master, current_user: user) + member = described_class.add_user(source, user, :maintainer, current_user: user) expect(source.users.reload).not_to include(user) expect(member).not_to be_persisted @@ -339,7 +339,7 @@ describe Member do expect(source.users).not_to include(user) expect(source.requesters.exists?(user_id: user)).to be_truthy - described_class.add_user(source, user, :master, current_user: user) + described_class.add_user(source, user, :maintainer, current_user: user) expect(source.users.reload).not_to include(user) expect(source.requesters.exists?(user_id: user)).to be_truthy @@ -356,9 +356,9 @@ describe Member do it 'updates the member' do expect(source.users).to include(user) - described_class.add_user(source, user, :master) + described_class.add_user(source, user, :maintainer) - expect(source.members.find_by(user_id: user).access_level).to eq(Gitlab::Access::MASTER) + expect(source.members.find_by(user_id: user).access_level).to eq(Gitlab::Access::MAINTAINER) end end @@ -366,9 +366,9 @@ describe Member do it 'updates the member' do expect(source.users).to include(user) - described_class.add_user(source, user, :master, current_user: admin) + described_class.add_user(source, user, :maintainer, current_user: admin) - expect(source.members.find_by(user_id: user).access_level).to eq(Gitlab::Access::MASTER) + expect(source.members.find_by(user_id: user).access_level).to eq(Gitlab::Access::MAINTAINER) end end @@ -376,7 +376,7 @@ describe Member do it 'does not update the member' do expect(source.users).to include(user) - described_class.add_user(source, user, :master, current_user: user) + described_class.add_user(source, user, :maintainer, current_user: user) expect(source.members.find_by(user_id: user).access_level).to eq(Gitlab::Access::DEVELOPER) end @@ -395,7 +395,7 @@ describe Member do let(:user2) { create(:user) } it 'returns a <Source>Member objects' do - members = described_class.add_users(source, [user1, user2], :master) + members = described_class.add_users(source, [user1, user2], :maintainer) expect(members).to be_a Array expect(members.size).to eq(2) @@ -404,7 +404,7 @@ describe Member do end it 'returns an empty array' do - members = described_class.add_users(source, [], :master) + members = described_class.add_users(source, [], :maintainer) expect(members).to be_a Array expect(members).to be_empty @@ -413,7 +413,7 @@ describe Member do it 'supports differents formats' do list = ['joe@local.test', admin, user1.id, user2.id.to_s] - members = described_class.add_users(source, list, :master) + members = described_class.add_users(source, list, :maintainer) expect(members.size).to eq(4) expect(members.first).to be_invite diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb index ffc78015f94..97959ed4304 100644 --- a/spec/models/members/group_member_spec.rb +++ b/spec/models/members/group_member_spec.rb @@ -21,7 +21,7 @@ describe GroupMember do described_class.add_users( group, [users.first.id, users.second], - described_class::MASTER + described_class::MAINTAINER ) expect(group.users).to include(users.first, users.second) diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 574eb468e4c..334d4f95f53 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -28,7 +28,7 @@ describe ProjectMember do expect(project.users).not_to include(user) - described_class.add_user(project, user, :master, current_user: project.owner) + described_class.add_user(project, user, :maintainer, current_user: project.owner) expect(project.users.reload).to include(user) end @@ -41,9 +41,9 @@ describe ProjectMember do end describe "#destroy" do - let(:owner) { create(:project_member, access_level: ProjectMember::MASTER) } + let(:owner) { create(:project_member, access_level: ProjectMember::MAINTAINER) } let(:project) { owner.project } - let(:master) { create(:project_member, project: project) } + let(:maintainer) { create(:project_member, project: project) } it "creates an expired event when left due to expiry" do expired = create(:project_member, project: project, expires_at: Time.now - 6.days) @@ -52,7 +52,7 @@ describe ProjectMember do end it "creates a left event when left due to leave" do - master.destroy + maintainer.destroy expect(Event.recent.first.action).to eq(Event::LEFT) end end @@ -95,7 +95,7 @@ describe ProjectMember do described_class.add_users_to_projects( [projects.first.id, projects.second.id], [users.first.id, users.second], - described_class::MASTER) + described_class::MAINTAINER) expect(projects.first.users).to include(users.first) expect(projects.first.users).to include(users.second) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index c7eead2bdaa..b0d9d03bf6c 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -724,7 +724,7 @@ describe MergeRequest do subject { merge_request } before do - subject.source_project.add_master(user) + subject.source_project.add_maintainer(user) end it "can't be removed when its a protected branch" do @@ -1199,7 +1199,7 @@ describe MergeRequest do end before do - project.add_master(current_user) + project.add_maintainer(current_user) ProcessCommitWorker.new.perform(project.id, current_user.id, @@ -1569,8 +1569,8 @@ describe MergeRequest do let(:merge_request) { create(:merge_request, source_project: project) } before do - merge_request.source_project.add_master(user) - merge_request.target_project.add_master(user) + merge_request.source_project.add_maintainer(user) + merge_request.target_project.add_maintainer(user) end context 'with multiple environments' do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index a2cb716cb93..947be44c903 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -144,8 +144,8 @@ describe Note do describe 'admin' do before do @p1.project_members.create(user: @u1, access_level: ProjectMember::REPORTER) - @p1.project_members.create(user: @u2, access_level: ProjectMember::MASTER) - @p2.project_members.create(user: @u3, access_level: ProjectMember::MASTER) + @p1.project_members.create(user: @u2, access_level: ProjectMember::MAINTAINER) + @p2.project_members.create(user: @u3, access_level: ProjectMember::MAINTAINER) end it { expect(Ability.allowed?(@u1, :admin_note, @p1)).to be_falsey } @@ -225,7 +225,7 @@ describe Note do describe "cross_reference_not_visible_for?" do let(:private_user) { create(:user) } - let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_master(private_user) } } + let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_maintainer(private_user) } } let(:private_issue) { create(:issue, project: private_project) } let(:ext_proj) { create(:project, :public) } diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb index 9e7e525b2c0..c289ee0859a 100644 --- a/spec/models/project_authorization_spec.rb +++ b/spec/models/project_authorization_spec.rb @@ -8,15 +8,15 @@ describe ProjectAuthorization do describe '.insert_authorizations' do it 'inserts the authorizations' do described_class - .insert_authorizations([[user.id, project1.id, Gitlab::Access::MASTER]]) + .insert_authorizations([[user.id, project1.id, Gitlab::Access::MAINTAINER]]) expect(user.project_authorizations.count).to eq(1) end it 'inserts rows in batches' do described_class.insert_authorizations([ - [user.id, project1.id, Gitlab::Access::MASTER], - [user.id, project2.id, Gitlab::Access::MASTER] + [user.id, project1.id, Gitlab::Access::MAINTAINER], + [user.id, project2.id, Gitlab::Access::MAINTAINER] ], 1) expect(user.project_authorizations.count).to eq(2) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index bbf37ca59b9..c01c7bc47b5 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -336,7 +336,7 @@ describe Project do end describe 'delegation' do - [:add_guest, :add_reporter, :add_developer, :add_master, :add_user, :add_users].each do |method| + [:add_guest, :add_reporter, :add_developer, :add_maintainer, :add_user, :add_users].each do |method| it { is_expected.to delegate_method(method).to(:team) } end @@ -1130,7 +1130,7 @@ describe Project do describe 'when a user has access to a project' do before do - project.add_user(user, Gitlab::Access::MASTER) + project.add_user(user, Gitlab::Access::MAINTAINER) end it { is_expected.to eq([project]) } @@ -3496,8 +3496,8 @@ describe Project do expect(project.protected_branches).not_to be_empty expect(project.default_branch).to eq(project.protected_branches.first.name) - expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) - expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) + expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) end end end @@ -3733,7 +3733,7 @@ describe Project do end it 'does not allow access if the user cannot merge the merge request' do - create(:protected_branch, :masters_can_push, project: target_project, name: 'target-branch') + create(:protected_branch, :maintainers_can_push, project: target_project, name: 'target-branch') expect(project.branch_allows_collaboration?(user, 'awesome-feature-1')) .to be_falsy diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 9978f3e9566..c4af17f4726 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" describe ProjectTeam do - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } let(:nonmember) { create(:user) } @@ -10,23 +10,23 @@ describe ProjectTeam do let(:project) { create(:project) } before do - project.add_master(master) + project.add_maintainer(maintainer) project.add_reporter(reporter) project.add_guest(guest) end describe 'members collection' do - it { expect(project.team.masters).to include(master) } - it { expect(project.team.masters).not_to include(guest) } - it { expect(project.team.masters).not_to include(reporter) } - it { expect(project.team.masters).not_to include(nonmember) } + it { expect(project.team.maintainers).to include(maintainer) } + it { expect(project.team.maintainers).not_to include(guest) } + it { expect(project.team.maintainers).not_to include(reporter) } + it { expect(project.team.maintainers).not_to include(nonmember) } end describe 'access methods' do - it { expect(project.team.master?(master)).to be_truthy } - it { expect(project.team.master?(guest)).to be_falsey } - it { expect(project.team.master?(reporter)).to be_falsey } - it { expect(project.team.master?(nonmember)).to be_falsey } + it { expect(project.team.maintainer?(maintainer)).to be_truthy } + it { expect(project.team.maintainer?(guest)).to be_falsey } + it { expect(project.team.maintainer?(reporter)).to be_falsey } + it { expect(project.team.maintainer?(nonmember)).to be_falsey } it { expect(project.team.member?(nonmember)).to be_falsey } it { expect(project.team.member?(guest)).to be_truthy } it { expect(project.team.member?(reporter, Gitlab::Access::REPORTER)).to be_truthy } @@ -40,35 +40,35 @@ describe ProjectTeam do let!(:project) { create(:project, group: group) } before do - group.add_master(master) + group.add_maintainer(maintainer) group.add_reporter(reporter) group.add_guest(guest) # If user is a group and a project member - GitLab uses highest permission - # So we add group guest as master and add group master as guest + # So we add group guest as maintainer and add group maintainer as guest # to this project to test highest access - project.add_master(guest) - project.add_guest(master) + project.add_maintainer(guest) + project.add_guest(maintainer) end describe 'members collection' do it { expect(project.team.reporters).to include(reporter) } - it { expect(project.team.masters).to include(master) } - it { expect(project.team.masters).to include(guest) } - it { expect(project.team.masters).not_to include(reporter) } - it { expect(project.team.masters).not_to include(nonmember) } + it { expect(project.team.maintainers).to include(maintainer) } + it { expect(project.team.maintainers).to include(guest) } + it { expect(project.team.maintainers).not_to include(reporter) } + it { expect(project.team.maintainers).not_to include(nonmember) } end describe 'access methods' do it { expect(project.team.reporter?(reporter)).to be_truthy } - it { expect(project.team.master?(master)).to be_truthy } - it { expect(project.team.master?(guest)).to be_truthy } - it { expect(project.team.master?(reporter)).to be_falsey } - it { expect(project.team.master?(nonmember)).to be_falsey } + it { expect(project.team.maintainer?(maintainer)).to be_truthy } + it { expect(project.team.maintainer?(guest)).to be_truthy } + it { expect(project.team.maintainer?(reporter)).to be_falsey } + it { expect(project.team.maintainer?(nonmember)).to be_falsey } it { expect(project.team.member?(nonmember)).to be_falsey } it { expect(project.team.member?(guest)).to be_truthy } - it { expect(project.team.member?(guest, Gitlab::Access::MASTER)).to be_truthy } - it { expect(project.team.member?(reporter, Gitlab::Access::MASTER)).to be_falsey } + it { expect(project.team.member?(guest, Gitlab::Access::MAINTAINER)).to be_truthy } + it { expect(project.team.member?(reporter, Gitlab::Access::MAINTAINER)).to be_falsey } it { expect(project.team.member?(nonmember, Gitlab::Access::GUEST)).to be_falsey } end end @@ -145,13 +145,13 @@ describe ProjectTeam do let(:requester) { create(:user) } before do - project.add_master(master) + project.add_maintainer(maintainer) project.add_reporter(reporter) project.add_guest(guest) project.request_access(requester) end - it { expect(project.team.find_member(master.id)).to be_a(ProjectMember) } + it { expect(project.team.find_member(maintainer.id)).to be_a(ProjectMember) } it { expect(project.team.find_member(reporter.id)).to be_a(ProjectMember) } it { expect(project.team.find_member(guest.id)).to be_a(ProjectMember) } it { expect(project.team.find_member(nonmember.id)).to be_nil } @@ -164,13 +164,13 @@ describe ProjectTeam do let(:requester) { create(:user) } before do - group.add_master(master) + group.add_maintainer(maintainer) group.add_reporter(reporter) group.add_guest(guest) group.request_access(requester) end - it { expect(project.team.find_member(master.id)).to be_a(GroupMember) } + it { expect(project.team.find_member(maintainer.id)).to be_a(GroupMember) } it { expect(project.team.find_member(reporter.id)).to be_a(GroupMember) } it { expect(project.team.find_member(guest.id)).to be_a(GroupMember) } it { expect(project.team.find_member(nonmember.id)).to be_nil } @@ -184,7 +184,7 @@ describe ProjectTeam do group = create(:group) project = create(:project, namespace: group) - group.add_master(user) + group.add_maintainer(user) expect(project.team.human_max_access(user.id)).to eq 'Maintainer' end @@ -210,13 +210,13 @@ describe ProjectTeam do context 'when project is not shared with group' do before do - project.add_master(master) + project.add_maintainer(maintainer) project.add_reporter(reporter) project.add_guest(guest) project.request_access(requester) end - it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::MASTER) } + it { expect(project.team.max_member_access(maintainer.id)).to eq(Gitlab::Access::MAINTAINER) } it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) } it { expect(project.team.max_member_access(guest.id)).to eq(Gitlab::Access::GUEST) } it { expect(project.team.max_member_access(nonmember.id)).to eq(Gitlab::Access::NO_ACCESS) } @@ -230,11 +230,11 @@ describe ProjectTeam do group: group, group_access: Gitlab::Access::DEVELOPER) - group.add_master(master) + group.add_maintainer(maintainer) group.add_reporter(reporter) end - it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::DEVELOPER) } + it { expect(project.team.max_member_access(maintainer.id)).to eq(Gitlab::Access::DEVELOPER) } it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) } it { expect(project.team.max_member_access(nonmember.id)).to eq(Gitlab::Access::NO_ACCESS) } it { expect(project.team.max_member_access(requester.id)).to eq(Gitlab::Access::NO_ACCESS) } @@ -244,7 +244,7 @@ describe ProjectTeam 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(maintainer.id)).to eq(Gitlab::Access::NO_ACCESS) } it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::NO_ACCESS) } end end @@ -257,13 +257,13 @@ describe ProjectTeam do end before do - group.add_master(master) + group.add_maintainer(maintainer) group.add_reporter(reporter) group.add_guest(guest) group.request_access(requester) end - it { expect(project.team.max_member_access(master.id)).to eq(Gitlab::Access::MASTER) } + it { expect(project.team.max_member_access(maintainer.id)).to eq(Gitlab::Access::MAINTAINER) } it { expect(project.team.max_member_access(reporter.id)).to eq(Gitlab::Access::REPORTER) } it { expect(project.team.max_member_access(guest.id)).to eq(Gitlab::Access::GUEST) } it { expect(project.team.max_member_access(nonmember.id)).to eq(Gitlab::Access::NO_ACCESS) } @@ -274,7 +274,7 @@ describe ProjectTeam do describe '#member?' do let(:group) { create(:group) } let(:developer) { create(:user) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:personal_project) do create(:project, namespace: developer.namespace) @@ -288,11 +288,11 @@ describe ProjectTeam do let(:shared_project) { create(:project) } before do - group.add_master(master) + group.add_maintainer(maintainer) group.add_developer(developer) members_project.add_developer(developer) - members_project.add_master(master) + members_project.add_maintainer(maintainer) create(:project_group_link, project: shared_project, group: group) end @@ -318,14 +318,14 @@ describe ProjectTeam do end it 'checks for the correct minimum level access' do - expect(group_project.team.member?(developer, Gitlab::Access::MASTER)).to be(false) - expect(group_project.team.member?(master, Gitlab::Access::MASTER)).to be(true) - expect(members_project.team.member?(developer, Gitlab::Access::MASTER)).to be(false) - expect(members_project.team.member?(master, Gitlab::Access::MASTER)).to be(true) - expect(shared_project.team.member?(developer, Gitlab::Access::MASTER)).to be(false) - expect(shared_project.team.member?(master, Gitlab::Access::MASTER)).to be(false) + expect(group_project.team.member?(developer, Gitlab::Access::MAINTAINER)).to be(false) + expect(group_project.team.member?(maintainer, Gitlab::Access::MAINTAINER)).to be(true) + expect(members_project.team.member?(developer, Gitlab::Access::MAINTAINER)).to be(false) + expect(members_project.team.member?(maintainer, Gitlab::Access::MAINTAINER)).to be(true) + expect(shared_project.team.member?(developer, Gitlab::Access::MAINTAINER)).to be(false) + expect(shared_project.team.member?(maintainer, Gitlab::Access::MAINTAINER)).to be(false) expect(shared_project.team.member?(developer, Gitlab::Access::DEVELOPER)).to be(true) - expect(shared_project.team.member?(master, Gitlab::Access::DEVELOPER)).to be(true) + expect(shared_project.team.member?(maintainer, Gitlab::Access::DEVELOPER)).to be(true) end end @@ -334,7 +334,7 @@ describe ProjectTeam do let(:group) { create(:group) } let(:second_group) { create(:group) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } @@ -347,23 +347,23 @@ describe ProjectTeam do let(:second_user_without_access) { create(:user) } let(:users) do - [master, reporter, promoted_guest, guest, group_developer, second_developer, user_without_access].map(&:id) + [maintainer, reporter, promoted_guest, guest, group_developer, second_developer, user_without_access].map(&:id) end let(:expected) do { - master.id => Gitlab::Access::MASTER, + maintainer.id => Gitlab::Access::MAINTAINER, reporter.id => Gitlab::Access::REPORTER, promoted_guest.id => Gitlab::Access::DEVELOPER, guest.id => Gitlab::Access::GUEST, group_developer.id => Gitlab::Access::DEVELOPER, - second_developer.id => Gitlab::Access::MASTER, + second_developer.id => Gitlab::Access::MAINTAINER, user_without_access.id => Gitlab::Access::NO_ACCESS } end before do - project.add_master(master) + project.add_maintainer(maintainer) project.add_reporter(reporter) project.add_guest(promoted_guest) project.add_guest(guest) @@ -373,16 +373,16 @@ describe ProjectTeam do group_access: Gitlab::Access::DEVELOPER ) - group.add_master(promoted_guest) + group.add_maintainer(promoted_guest) group.add_developer(group_developer) group.add_developer(second_developer) project.project_group_links.create( group: second_group, - group_access: Gitlab::Access::MASTER + group_access: Gitlab::Access::MAINTAINER ) - second_group.add_master(second_developer) + second_group.add_maintainer(second_developer) end it 'returns correct roles for different users' do diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index a3c20b3b3c1..a544940800a 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require "spec_helper" describe ProjectWiki do @@ -10,7 +11,6 @@ describe ProjectWiki do subject { project_wiki } - it { is_expected.to delegate_method(:empty?).to :pages } it { is_expected.to delegate_method(:repository_storage).to :project } it { is_expected.to delegate_method(:hashed_storage?).to :project } @@ -92,11 +92,19 @@ describe ProjectWiki do context "when the wiki has pages" do before do project_wiki.create_page("index", "This is an awesome new Gollum Wiki") + project_wiki.create_page("another-page", "This is another page") end describe '#empty?' do subject { super().empty? } it { is_expected.to be_falsey } + + # Re-enable this when https://gitlab.com/gitlab-org/gitaly/issues/1204 is fixed + xit 'only instantiates a Wiki page once' do + expect(WikiPage).to receive(:new).once.and_call_original + + subject + end end end end diff --git a/spec/models/protected_branch/merge_access_level_spec.rb b/spec/models/protected_branch/merge_access_level_spec.rb index f70503eadbc..612e4a0e332 100644 --- a/spec/models/protected_branch/merge_access_level_spec.rb +++ b/spec/models/protected_branch/merge_access_level_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' describe ProtectedBranch::MergeAccessLevel do - it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MASTER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) } + it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MAINTAINER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) } end diff --git a/spec/models/protected_branch/push_access_level_spec.rb b/spec/models/protected_branch/push_access_level_spec.rb index f161f345761..9ccdc22fd41 100644 --- a/spec/models/protected_branch/push_access_level_spec.rb +++ b/spec/models/protected_branch/push_access_level_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' describe ProtectedBranch::PushAccessLevel do - it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MASTER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) } + it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MAINTAINER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) } end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index d060ab923d1..04d00023b8a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -151,7 +151,9 @@ describe Repository do it { is_expected.to eq(['v1.1.0', 'v1.0.0', annotated_tag_name]) } after do - repository.rugged.tags.delete(annotated_tag_name) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.tags.delete(annotated_tag_name) + end end end end @@ -431,6 +433,18 @@ describe Repository do it { is_expected.to be_falsey } end + + context 'non merged branch' do + subject { repository.merged_to_root_ref?('fix') } + + it { is_expected.to be_falsey } + end + + context 'non existent branch' do + subject { repository.merged_to_root_ref?('non_existent_branch') } + + it { is_expected.to be_nil } + end end describe '#can_be_merged?' do @@ -452,17 +466,11 @@ describe Repository do it { is_expected.to be_falsey } end - context 'non merged branch' do - subject { repository.merged_to_root_ref?('fix') } + context 'submodule changes that confuse rugged' do + subject { repository.can_be_merged?('update-gitlab-shell-v-6-0-1', 'update-gitlab-shell-v-6-0-3') } it { is_expected.to be_falsey } end - - context 'non existent branch' do - subject { repository.merged_to_root_ref?('non_existent_branch') } - - it { is_expected.to be_nil } - end end describe '#commit' do @@ -2225,8 +2233,11 @@ describe Repository do create_remote_branch('joe', 'remote_branch', masterrev) repository.add_branch(user, 'local_branch', masterrev.id) - expect(repository.remote_branches('joe').any? { |branch| branch.name == 'local_branch' }).to eq(false) - expect(repository.remote_branches('joe').any? { |branch| branch.name == 'remote_branch' }).to eq(true) + # TODO: move this test to gitaly https://gitlab.com/gitlab-org/gitaly/issues/1243 + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + expect(repository.remote_branches('joe').any? { |branch| branch.name == 'local_branch' }).to eq(false) + expect(repository.remote_branches('joe').any? { |branch| branch.name == 'remote_branch' }).to eq(true) + end end end diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb index f29abcf536e..bd498269798 100644 --- a/spec/models/todo_spec.rb +++ b/spec/models/todo_spec.rb @@ -7,7 +7,6 @@ describe Todo do it { is_expected.to belong_to(:author).class_name("User") } it { is_expected.to belong_to(:note) } it { is_expected.to belong_to(:project) } - it { is_expected.to belong_to(:group) } it { is_expected.to belong_to(:target).touch(true) } it { is_expected.to belong_to(:user) } end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6d7b733dd4f..fc46551c3be 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -700,7 +700,7 @@ describe User do @project = create(:project, namespace: @user.namespace) @project_2 = create(:project, group: create(:group)) do |project| - project.add_master(@user) + project.add_maintainer(@user) end @project_3 = create(:project, group: create(:group)) do |project| project.add_developer(@user) @@ -836,7 +836,7 @@ describe User do before do # add user to project - project.add_master(user) + project.add_maintainer(user) # create invite to projet create(:project_member, :developer, project: project, invite_token: '1234', invite_email: 'inviteduser1@example.com') @@ -1581,8 +1581,8 @@ describe User do let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) } before do - project1.add_master(subject) - project2.add_master(subject) + project1.add_maintainer(subject) + project2.add_maintainer(subject) end it "includes IDs for projects the user has pushed to" do @@ -1663,8 +1663,8 @@ describe User do let!(:project) { create(:project, group: project_group) } before do - private_group.add_user(user, Gitlab::Access::MASTER) - project.add_master(user) + private_group.add_user(user, Gitlab::Access::MAINTAINER) + project.add_maintainer(user) end subject { user.authorized_groups } @@ -1678,7 +1678,7 @@ describe User do let!(:child_group) { create(:group, parent: parent_group) } before do - parent_group.add_user(user, Gitlab::Access::MASTER) + parent_group.add_user(user, Gitlab::Access::MAINTAINER) end subject { user.membership_groups } @@ -1696,7 +1696,7 @@ describe User do it 'includes projects that belong to a user, but no other projects' do owned = create(:project, :private, namespace: user.namespace) - member = create(:project, :private).tap { |p| p.add_master(user) } + member = create(:project, :private).tap { |p| p.add_maintainer(user) } other = create(:project) expect(subject).to include(owned) @@ -1726,11 +1726,11 @@ describe User do .to contain_exactly(project) end - it 'includes projects for which the user is a master' do + it 'includes projects for which the user is a maintainer' do user = create(:user) project = create(:project, :private) - project.add_master(user) + project.add_maintainer(user) expect(user.authorized_projects(Gitlab::Access::REPORTER)) .to contain_exactly(project) @@ -1824,10 +1824,10 @@ describe User do it 'includes projects for which the user access level is above or equal to reporter' do reporter_project = create(:project) { |p| p.add_reporter(user) } developer_project = create(:project) { |p| p.add_developer(user) } - master_project = create(:project) { |p| p.add_master(user) } + maintainer_project = create(:project) { |p| p.add_maintainer(user) } - expect(user.projects_where_can_admin_issues.to_a).to match_array([master_project, developer_project, reporter_project]) - expect(user.can?(:admin_issue, master_project)).to eq(true) + expect(user.projects_where_can_admin_issues.to_a).to match_array([maintainer_project, developer_project, reporter_project]) + expect(user.can?(:admin_issue, maintainer_project)).to eq(true) expect(user.can?(:admin_issue, developer_project)).to eq(true) expect(user.can?(:admin_issue, reporter_project)).to eq(true) end @@ -1907,9 +1907,9 @@ describe User do end shared_examples :member do - context 'when the user is a master' do + context 'when the user is a maintainer' do before do - add_user(:master) + add_user(:maintainer) end it 'loads' do @@ -2668,20 +2668,20 @@ describe User do let(:user) { create(:user) } let(:group) { create(:group) } let(:owner_project) { create(:project, group: group) } - let(:master_project) { create(:project) } + let(:maintainer_project) { create(:project) } let(:reporter_project) { create(:project) } let(:developer_project) { create(:project) } let(:guest_project) { create(:project) } let(:no_access_project) { create(:project) } let(:projects) do - [owner_project, master_project, reporter_project, developer_project, guest_project, no_access_project].map(&:id) + [owner_project, maintainer_project, reporter_project, developer_project, guest_project, no_access_project].map(&:id) end let(:expected) do { owner_project.id => Gitlab::Access::OWNER, - master_project.id => Gitlab::Access::MASTER, + maintainer_project.id => Gitlab::Access::MAINTAINER, reporter_project.id => Gitlab::Access::REPORTER, developer_project.id => Gitlab::Access::DEVELOPER, guest_project.id => Gitlab::Access::GUEST, @@ -2691,7 +2691,7 @@ describe User do before do create(:group_member, user: user, group: group) - master_project.add_master(user) + maintainer_project.add_maintainer(user) reporter_project.add_reporter(user) developer_project.add_developer(user) guest_project.add_guest(user) @@ -2718,14 +2718,14 @@ describe User do end it 'only requests the extra projects when uncached projects are passed' do - second_master_project = create(:project) + second_maintainer_project = create(:project) second_developer_project = create(:project) - second_master_project.add_master(user) + second_maintainer_project.add_maintainer(user) second_developer_project.add_developer(user) - all_projects = projects + [second_master_project.id, second_developer_project.id] + all_projects = projects + [second_maintainer_project.id, second_developer_project.id] - expected_all = expected.merge(second_master_project.id => Gitlab::Access::MASTER, + expected_all = expected.merge(second_maintainer_project.id => Gitlab::Access::MAINTAINER, second_developer_project.id => Gitlab::Access::DEVELOPER) access_levels(projects) @@ -2733,7 +2733,7 @@ describe User do queries = ActiveRecord::QueryRecorder.new { access_levels(all_projects) } expect(queries.count).to eq(1) - expect(queries.log_message).to match(/\W(#{second_master_project.id}, #{second_developer_project.id})\W/) + expect(queries.log_message).to match(/\W(#{second_maintainer_project.id}, #{second_developer_project.id})\W/) expect(access_levels(all_projects)).to eq(expected_all) end end @@ -2747,20 +2747,20 @@ describe User do shared_examples 'max member access for groups' do let(:user) { create(:user) } let(:owner_group) { create(:group) } - let(:master_group) { create(:group) } + let(:maintainer_group) { create(:group) } let(:reporter_group) { create(:group) } let(:developer_group) { create(:group) } let(:guest_group) { create(:group) } let(:no_access_group) { create(:group) } let(:groups) do - [owner_group, master_group, reporter_group, developer_group, guest_group, no_access_group].map(&:id) + [owner_group, maintainer_group, reporter_group, developer_group, guest_group, no_access_group].map(&:id) end let(:expected) do { owner_group.id => Gitlab::Access::OWNER, - master_group.id => Gitlab::Access::MASTER, + maintainer_group.id => Gitlab::Access::MAINTAINER, reporter_group.id => Gitlab::Access::REPORTER, developer_group.id => Gitlab::Access::DEVELOPER, guest_group.id => Gitlab::Access::GUEST, @@ -2770,7 +2770,7 @@ describe User do before do owner_group.add_owner(user) - master_group.add_master(user) + maintainer_group.add_maintainer(user) reporter_group.add_reporter(user) developer_group.add_developer(user) guest_group.add_guest(user) @@ -2797,14 +2797,14 @@ describe User do end it 'only requests the extra groups when uncached groups are passed' do - second_master_group = create(:group) + second_maintainer_group = create(:group) second_developer_group = create(:group) - second_master_group.add_master(user) + second_maintainer_group.add_maintainer(user) second_developer_group.add_developer(user) - all_groups = groups + [second_master_group.id, second_developer_group.id] + all_groups = groups + [second_maintainer_group.id, second_developer_group.id] - expected_all = expected.merge(second_master_group.id => Gitlab::Access::MASTER, + expected_all = expected.merge(second_maintainer_group.id => Gitlab::Access::MAINTAINER, second_developer_group.id => Gitlab::Access::DEVELOPER) access_levels(groups) @@ -2812,7 +2812,7 @@ describe User do queries = ActiveRecord::QueryRecorder.new { access_levels(all_groups) } expect(queries.count).to eq(1) - expect(queries.log_message).to match(/\W(#{second_master_group.id}, #{second_developer_group.id})\W/) + expect(queries.log_message).to match(/\W(#{second_maintainer_group.id}, #{second_developer_group.id})\W/) expect(access_levels(all_groups)).to eq(expected_all) end end diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index eead55d33ca..79a616899fa 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -204,18 +204,18 @@ describe Ci::BuildPolicy do end end - context 'when a master erases a build' do + context 'when a maintainer erases a build' do before do - project.add_master(user) + project.add_maintainer(user) end - context 'when masters can push to the branch' do + context 'when maintainers can push to the branch' do before do - create(:protected_branch, :masters_can_push, + create(:protected_branch, :maintainers_can_push, name: build.ref, project: project) end - context 'when the build was created by the master' do + context 'when the build was created by the maintainer' do let(:owner) { user } it { expect(policy).to be_allowed :erase_build } diff --git a/spec/policies/ci/pipeline_schedule_policy_spec.rb b/spec/policies/ci/pipeline_schedule_policy_spec.rb index c0c3eda4911..f1d3cd04e32 100644 --- a/spec/policies/ci/pipeline_schedule_policy_spec.rb +++ b/spec/policies/ci/pipeline_schedule_policy_spec.rb @@ -77,9 +77,9 @@ describe Ci::PipelineSchedulePolicy, :models do end end - describe 'rules for a master' do + describe 'rules for a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it 'includes abilities to do do all operations on pipeline schedule' do @@ -93,8 +93,8 @@ describe Ci::PipelineSchedulePolicy, :models do let(:owner) { create(:user) } before do - project.add_master(owner) - project.add_master(user) + project.add_maintainer(owner) + project.add_maintainer(user) pipeline_schedule.update(owner: owner) end diff --git a/spec/policies/ci/trigger_policy_spec.rb b/spec/policies/ci/trigger_policy_spec.rb index 14630748c90..d8a63066265 100644 --- a/spec/policies/ci/trigger_policy_spec.rb +++ b/spec/policies/ci/trigger_policy_spec.rb @@ -43,9 +43,9 @@ describe Ci::TriggerPolicy do context 'when owner is undefined' do let(:owner) { nil } - context 'when user is master of the project' do + context 'when user is maintainer of the project' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'allows to admin and manage trigger' @@ -67,9 +67,9 @@ describe Ci::TriggerPolicy do context 'when owner is an user' do let(:owner) { user } - context 'when user is master of the project' do + context 'when user is maintainer of the project' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'allows to admin and manage trigger' @@ -79,9 +79,9 @@ describe Ci::TriggerPolicy do context 'when owner is another user' do let(:owner) { create(:user) } - context 'when user is master of the project' do + context 'when user is maintainer of the project' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'allows to manage trigger' diff --git a/spec/policies/clusters/cluster_policy_spec.rb b/spec/policies/clusters/cluster_policy_spec.rb index 4207f42b07f..ced969830d8 100644 --- a/spec/policies/clusters/cluster_policy_spec.rb +++ b/spec/policies/clusters/cluster_policy_spec.rb @@ -16,9 +16,9 @@ describe Clusters::ClusterPolicy, :models do it { expect(policy).to be_disallowed :admin_cluster } end - context 'when master' do + context 'when maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it { expect(policy).to be_allowed :update_cluster } diff --git a/spec/policies/deploy_key_policy_spec.rb b/spec/policies/deploy_key_policy_spec.rb index ca7b7fe7ef7..e7263d49613 100644 --- a/spec/policies/deploy_key_policy_spec.rb +++ b/spec/policies/deploy_key_policy_spec.rb @@ -12,7 +12,7 @@ describe DeployKeyPolicy do let(:project) { create(:project_empty_repo) } before do - project.add_master(current_user) + project.add_maintainer(current_user) project.deploy_keys << deploy_key end diff --git a/spec/policies/deploy_token_policy_spec.rb b/spec/policies/deploy_token_policy_spec.rb index eea287d895e..cef5a4a22bc 100644 --- a/spec/policies/deploy_token_policy_spec.rb +++ b/spec/policies/deploy_token_policy_spec.rb @@ -8,15 +8,15 @@ describe DeployTokenPolicy do subject { described_class.new(current_user, deploy_token) } describe 'creating a deploy key' do - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(current_user) + project.add_maintainer(current_user) end it { is_expected.to be_allowed(:create_deploy_token) } end - context 'when user is not master' do + context 'when user is not maintainer' do before do project.add_developer(current_user) end @@ -26,15 +26,15 @@ describe DeployTokenPolicy do end describe 'updating a deploy key' do - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(current_user) + project.add_maintainer(current_user) end it { is_expected.to be_allowed(:update_deploy_token) } end - context 'when user is not master' do + context 'when user is not maintainer' do before do project.add_developer(current_user) end diff --git a/spec/policies/environment_policy_spec.rb b/spec/policies/environment_policy_spec.rb index de4cb5b30c5..0442b032e89 100644 --- a/spec/policies/environment_policy_spec.rb +++ b/spec/policies/environment_policy_spec.rb @@ -1,57 +1,101 @@ require 'spec_helper' describe EnvironmentPolicy do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } + using RSpec::Parameterized::TableSyntax - let(:environment) do - create(:environment, :with_review_app, project: project) - end + let(:user) { create(:user) } let(:policy) do described_class.new(user, environment) end describe '#rules' do - context 'when user does not have access to the project' do - let(:project) { create(:project, :private, :repository) } + shared_examples 'project permissions' do + context 'with stop action' do + let(:environment) do + create(:environment, :with_review_app, project: project) + end - it 'does not include ability to stop environment' do - expect(policy).to be_disallowed :stop_environment - end - end + where(:access_level, :allowed?) do + nil | false + :guest | false + :reporter | false + :developer | true + :maintainer | true + end - context 'when anonymous user has access to the project' do - let(:project) { create(:project, :public, :repository) } + with_them do + before do + project.add_user(user, access_level) unless access_level.nil? + end - it 'does not include ability to stop environment' do - expect(policy).to be_disallowed :stop_environment - end - end + it { expect(policy.allowed?(:stop_environment)).to be allowed? } + end - context 'when team member has access to the project' do - let(:project) { create(:project, :public, :repository) } + context 'when an admin user' do + let(:user) { create(:user, :admin) } - before do - project.add_developer(user) - end + it { expect(policy).to be_allowed :stop_environment } + end + + context 'with protected branch' do + with_them do + before do + project.add_user(user, access_level) unless access_level.nil? + create(:protected_branch, :no_one_can_push, + name: 'master', project: project) + end - context 'when team member has ability to stop environment' do - it 'does includes ability to stop environment' do - expect(policy).to be_allowed :stop_environment + it { expect(policy).to be_disallowed :stop_environment } + end + + context 'when an admin user' do + let(:user) { create(:user, :admin) } + + it { expect(policy).to be_allowed :stop_environment } + end end end - context 'when team member has no ability to stop environment' do - before do - create(:protected_branch, :no_one_can_push, - name: 'master', project: project) + context 'without stop action' do + let(:environment) do + create(:environment, project: project) + end + + where(:access_level, :allowed?) do + nil | false + :guest | false + :reporter | false + :developer | false + :maintainer | true end - it 'does not include ability to stop environment' do - expect(policy).to be_disallowed :stop_environment + with_them do + before do + project.add_user(user, access_level) unless access_level.nil? + end + + it { expect(policy.allowed?(:stop_environment)).to be allowed? } + end + + context 'when an admin user' do + let(:user) { create(:user, :admin) } + + it { expect(policy).to be_allowed :stop_environment } end end end + + context 'when project is public' do + let(:project) { create(:project, :public, :repository) } + + include_examples 'project permissions' + end + + context 'when project is private' do + let(:project) { create(:project, :private, :repository) } + + include_examples 'project permissions' + end end end diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb index 873673b50ef..a2047b54deb 100644 --- a/spec/policies/global_policy_spec.rb +++ b/spec/policies/global_policy_spec.rb @@ -65,12 +65,12 @@ describe GlobalPolicy do it { is_expected.not_to be_allowed(:create_fork) } end - context "when user is a master in a group" do + context "when user is a maintainer in a group" do let(:group) { create(:group) } let(:current_user) { create(:user, projects_limit: 0) } before do - group.add_master(current_user) + group.add_maintainer(current_user) end it { is_expected.to be_allowed(:create_fork) } diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index d6d340bd806..35951251bc5 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -4,7 +4,7 @@ describe GroupPolicy do let(:guest) { create(:user) } let(:reporter) { create(:user) } let(:developer) { create(:user) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:owner) { create(:user) } let(:admin) { create(:admin) } let(:group) { create(:group, :private) } @@ -19,7 +19,7 @@ describe GroupPolicy do let(:developer_permissions) { [:admin_milestones] } - let(:master_permissions) do + let(:maintainer_permissions) do [ :create_projects ] @@ -39,7 +39,7 @@ describe GroupPolicy do group.add_guest(guest) group.add_reporter(reporter) group.add_developer(developer) - group.add_master(master) + group.add_maintainer(maintainer) group.add_owner(owner) end @@ -62,7 +62,7 @@ describe GroupPolicy do expect_disallowed(:upload_file) expect_disallowed(*reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) expect_disallowed(:read_namespace) end @@ -97,7 +97,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_disallowed(*reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -109,7 +109,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -121,19 +121,19 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end - context 'master' do - let(:current_user) { master } + context 'maintainer' do + let(:current_user) { maintainer } it do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -147,7 +147,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_allowed(*owner_permissions) end end @@ -161,7 +161,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_allowed(*owner_permissions) end end @@ -203,7 +203,7 @@ describe GroupPolicy do nested_group.add_guest(guest) nested_group.add_guest(reporter) nested_group.add_guest(developer) - nested_group.add_guest(master) + nested_group.add_guest(maintainer) group.owners.destroy_all @@ -220,7 +220,7 @@ describe GroupPolicy do expect_disallowed(*guest_permissions) expect_disallowed(*reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -232,7 +232,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_disallowed(*reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -244,7 +244,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -256,19 +256,19 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end - context 'master' do - let(:current_user) { master } + context 'maintainer' do + let(:current_user) { maintainer } it do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end end @@ -282,7 +282,7 @@ describe GroupPolicy do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_allowed(*owner_permissions) end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 6d4676c25a5..dd3fa4e6a51 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -4,7 +4,7 @@ describe ProjectPolicy do set(:guest) { create(:user) } set(:reporter) { create(:user) } set(:developer) { create(:user) } - set(:master) { create(:user) } + set(:maintainer) { create(:user) } set(:owner) { create(:user) } set(:admin) { create(:admin) } let(:project) { create(:project, :public, namespace: owner.namespace) } @@ -42,7 +42,7 @@ describe ProjectPolicy do ] end - let(:base_master_permissions) do + let(:base_maintainer_permissions) do %i[ push_to_delete_protected_branch update_project_snippet update_environment update_deployment admin_project_snippet @@ -70,15 +70,15 @@ describe ProjectPolicy do # Used in EE specs let(:additional_guest_permissions) { [] } let(:additional_reporter_permissions) { [] } - let(:additional_master_permissions) { [] } + let(:additional_maintainer_permissions) { [] } let(:guest_permissions) { base_guest_permissions + additional_guest_permissions } let(:reporter_permissions) { base_reporter_permissions + additional_reporter_permissions } - let(:master_permissions) { base_master_permissions + additional_master_permissions } + let(:maintainer_permissions) { base_maintainer_permissions + additional_maintainer_permissions } before do project.add_guest(guest) - project.add_master(master) + project.add_maintainer(maintainer) project.add_developer(developer) project.add_reporter(reporter) end @@ -276,7 +276,7 @@ describe ProjectPolicy do expect_disallowed(*reporter_public_build_permissions) expect_disallowed(*team_member_reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end @@ -326,7 +326,7 @@ describe ProjectPolicy do expect_allowed(*reporter_permissions) expect_allowed(*team_member_reporter_permissions) expect_disallowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end @@ -347,7 +347,7 @@ describe ProjectPolicy do expect_allowed(*reporter_permissions) expect_allowed(*team_member_reporter_permissions) expect_allowed(*developer_permissions) - expect_disallowed(*master_permissions) + expect_disallowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end @@ -357,23 +357,23 @@ describe ProjectPolicy do end end - shared_examples 'project policies as master' do + shared_examples 'project policies as maintainer' do context 'abilities for non-public projects' do let(:project) { create(:project, namespace: owner.namespace) } - subject { described_class.new(master, project) } + subject { described_class.new(maintainer, project) } it do expect_allowed(*guest_permissions) expect_allowed(*reporter_permissions) expect_allowed(*team_member_reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_disallowed(*owner_permissions) end it_behaves_like 'archived project policies' do - let(:regular_abilities) { master_permissions } + let(:regular_abilities) { maintainer_permissions } end end end @@ -389,7 +389,7 @@ describe ProjectPolicy do expect_allowed(*reporter_permissions) expect_allowed(*team_member_reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_allowed(*owner_permissions) end @@ -410,7 +410,7 @@ describe ProjectPolicy do expect_allowed(*reporter_permissions) expect_disallowed(*team_member_reporter_permissions) expect_allowed(*developer_permissions) - expect_allowed(*master_permissions) + expect_allowed(*maintainer_permissions) expect_allowed(*owner_permissions) end @@ -424,7 +424,7 @@ describe ProjectPolicy do it_behaves_like 'project policies as guest' it_behaves_like 'project policies as reporter' it_behaves_like 'project policies as developer' - it_behaves_like 'project policies as master' + it_behaves_like 'project policies as maintainer' it_behaves_like 'project policies as owner' it_behaves_like 'project policies as admin' diff --git a/spec/policies/protected_branch_policy_spec.rb b/spec/policies/protected_branch_policy_spec.rb index b39de42d721..1587196754d 100644 --- a/spec/policies/protected_branch_policy_spec.rb +++ b/spec/policies/protected_branch_policy_spec.rb @@ -8,8 +8,8 @@ describe ProtectedBranchPolicy do subject { described_class.new(user, protected_branch) } - it 'branches can be updated via project masters' do - project.add_master(user) + it 'branches can be updated via project maintainers' do + project.add_maintainer(user) is_expected.to be_allowed(:update_protected_branch) end diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index e3b37739e8e..46ba6f442f5 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -270,7 +270,7 @@ describe MergeRequestPresenter do context 'when can create issue and issues enabled' do it 'returns path' do allow(project).to receive(:issues_enabled?) { true } - project.add_master(user) + project.add_maintainer(user) is_expected .to eq("/#{resource.project.full_path}/issues/new?merge_request_to_resolve_discussions_of=#{resource.iid}") @@ -288,7 +288,7 @@ describe MergeRequestPresenter do context 'when issues disabled' do it 'returns nil' do allow(project).to receive(:issues_enabled?) { false } - project.add_master(user) + project.add_maintainer(user) is_expected.to be_nil end @@ -307,7 +307,7 @@ describe MergeRequestPresenter do context 'when merge request enabled and has permission' do it 'has remove_wip_path' do allow(project).to receive(:merge_requests_enabled?) { true } - project.add_master(user) + project.add_maintainer(user) is_expected .to eq("/#{resource.project.full_path}/merge_requests/#{resource.iid}/remove_wip") diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb index 830d2ee3b20..01085dbcb49 100644 --- a/spec/presenters/project_presenter_spec.rb +++ b/spec/presenters/project_presenter_spec.rb @@ -326,7 +326,7 @@ describe ProjectPresenter do context 'when user can admin pipeline and CI yml does not exists' do it 'returns anchor data' do - project.add_master(user) + project.add_maintainer(user) allow(project).to receive(:auto_devops_enabled?).and_return(false) allow(project.repository).to receive(:gitlab_ci_yml).and_return(nil) @@ -340,7 +340,7 @@ describe ProjectPresenter do describe '#kubernetes_cluster_anchor_data' do context 'when user can create Kubernetes cluster' do it 'returns link to cluster if only one exists' do - project.add_master(user) + project.add_maintainer(user) cluster = create(:cluster, projects: [project]) expect(presenter.kubernetes_cluster_anchor_data).to eq(OpenStruct.new(enabled: true, @@ -349,7 +349,7 @@ describe ProjectPresenter do end it 'returns link to clusters page if more than one exists' do - project.add_master(user) + project.add_maintainer(user) create(:cluster, :production_environment, projects: [project]) create(:cluster, projects: [project]) @@ -359,7 +359,7 @@ describe ProjectPresenter do end it 'returns link to create a cluster if no cluster exists' do - project.add_master(user) + project.add_maintainer(user) expect(presenter.kubernetes_cluster_anchor_data).to eq(OpenStruct.new(enabled: false, label: 'Add Kubernetes cluster', diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb index ffca7ab8e45..e13129967b2 100644 --- a/spec/requests/api/access_requests_spec.rb +++ b/spec/requests/api/access_requests_spec.rb @@ -1,15 +1,15 @@ require 'spec_helper' describe API::AccessRequests do - set(:master) { create(:user) } + set(:maintainer) { create(:user) } set(:developer) { create(:user) } set(:access_requester) { create(:user) } set(:stranger) { create(:user) } set(:project) do - create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| + create(:project, :public, :access_requestable, creator_id: maintainer.id, namespace: maintainer.namespace) do |project| project.add_developer(developer) - project.add_master(master) + project.add_maintainer(maintainer) project.request_access(access_requester) end end @@ -17,7 +17,7 @@ describe API::AccessRequests do set(:group) do create(:group, :public, :access_requestable) do |group| group.add_developer(developer) - group.add_owner(master) + group.add_owner(maintainer) group.request_access(access_requester) end end @@ -28,7 +28,7 @@ describe API::AccessRequests do let(:route) { get api("/#{source_type.pluralize}/#{source.id}/access_requests", stranger) } end - context 'when authenticated as a non-master/owner' do + context 'when authenticated as a non-maintainer/owner' do %i[developer access_requester stranger].each do |type| context "as a #{type}" do it 'returns 403' do @@ -41,9 +41,9 @@ describe API::AccessRequests do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'returns access requesters' do - get api("/#{source_type.pluralize}/#{source.id}/access_requests", master) + get api("/#{source_type.pluralize}/#{source.id}/access_requests", maintainer) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers @@ -61,7 +61,7 @@ describe API::AccessRequests do end context 'when authenticated as a member' do - %i[developer master].each do |type| + %i[developer maintainer].each do |type| context "as a #{type}" do it 'returns 403' do expect do @@ -128,7 +128,7 @@ describe API::AccessRequests do let(:route) { put api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}/approve", stranger) } end - context 'when authenticated as a non-master/owner' do + context 'when authenticated as a non-maintainer/owner' do %i[developer access_requester stranger].each do |type| context "as a #{type}" do it 'returns 403' do @@ -141,11 +141,11 @@ describe API::AccessRequests do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'returns 201' do expect do - put api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}/approve", master), - access_level: Member::MASTER + put api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}/approve", maintainer), + access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(201) end.to change { source.members.count }.by(1) @@ -158,13 +158,13 @@ describe API::AccessRequests do expect(json_response['web_url']).to eq(Gitlab::Routing.url_helpers.user_url(access_requester)) # Member attributes - expect(json_response['access_level']).to eq(Member::MASTER) + expect(json_response['access_level']).to eq(Member::MAINTAINER) end context 'user_id does not match an existing access requester' do it 'returns 404' do expect do - put api("/#{source_type.pluralize}/#{source.id}/access_requests/#{stranger.id}/approve", master) + put api("/#{source_type.pluralize}/#{source.id}/access_requests/#{stranger.id}/approve", maintainer) expect(response).to have_gitlab_http_status(404) end.not_to change { source.members.count } @@ -180,7 +180,7 @@ describe API::AccessRequests do let(:route) { delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", stranger) } end - context 'when authenticated as a non-master/owner' do + context 'when authenticated as a non-maintainer/owner' do %i[developer stranger].each do |type| context "as a #{type}" do it 'returns 403' do @@ -203,10 +203,10 @@ describe API::AccessRequests do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'deletes the access requester' do expect do - delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", master) + delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{access_requester.id}", maintainer) expect(response).to have_gitlab_http_status(204) end.to change { source.requesters.count }.by(-1) @@ -215,7 +215,7 @@ describe API::AccessRequests do context 'user_id matches a member, not an access requester' do it 'returns 404' do expect do - delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{developer.id}", master) + delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{developer.id}", maintainer) expect(response).to have_gitlab_http_status(404) end.not_to change { source.requesters.count } @@ -225,7 +225,7 @@ describe API::AccessRequests do context 'user_id does not match an existing access requester' do it 'returns 404' do expect do - delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{stranger.id}", master) + delete api("/#{source_type.pluralize}/#{source.id}/access_requests/#{stranger.id}", maintainer) expect(response).to have_gitlab_http_status(404) end.not_to change { source.requesters.count } diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index 5adfb33677f..0921fecb933 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -10,7 +10,7 @@ describe API::AwardEmoji do set(:note) { create(:note, project: project, noteable: issue) } before do - project.add_master(user) + project.add_maintainer(user) end describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb index ae64a9ca162..e232e2e04ee 100644 --- a/spec/requests/api/badges_spec.rb +++ b/spec/requests/api/badges_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe API::Badges do - let(:master) { create(:user, username: 'master_user') } + let(:maintainer) { create(:user, username: 'maintainer_user') } let(:developer) { create(:user) } let(:access_requester) { create(:user) } let(:stranger) { create(:user) } @@ -25,7 +25,7 @@ describe API::Badges do let(:route) { get api("/#{source_type.pluralize}/#{source.id}/badges", stranger) } end - %i[master developer access_requester stranger].each do |type| + %i[maintainer developer access_requester stranger].each do |type| context "when authenticated as a #{type}" do it 'returns 200' do user = public_send(type) @@ -43,16 +43,16 @@ describe API::Badges do it 'avoids N+1 queries' do # Establish baseline - get api("/#{source_type.pluralize}/#{source.id}/badges", master) + get api("/#{source_type.pluralize}/#{source.id}/badges", maintainer) control = ActiveRecord::QueryRecorder.new do - get api("/#{source_type.pluralize}/#{source.id}/badges", master) + get api("/#{source_type.pluralize}/#{source.id}/badges", maintainer) end project.add_developer(create(:user)) expect do - get api("/#{source_type.pluralize}/#{source.id}/badges", master) + get api("/#{source_type.pluralize}/#{source.id}/badges", maintainer) end.not_to exceed_query_limit(control) end end @@ -69,7 +69,7 @@ describe API::Badges do end context 'when authenticated as a non-member' do - %i[master developer access_requester stranger].each do |type| + %i[maintainer developer access_requester stranger].each do |type| let(:badge) { source.badges.first } context "as a #{type}" do @@ -122,10 +122,10 @@ describe API::Badges do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'creates a new badge' do expect do - post api("/#{source_type.pluralize}/#{source.id}/badges", master), + post api("/#{source_type.pluralize}/#{source.id}/badges", maintainer), link_url: example_url, image_url: example_url2 expect(response).to have_gitlab_http_status(201) @@ -138,21 +138,21 @@ describe API::Badges do end it 'returns 400 when link_url is not given' do - post api("/#{source_type.pluralize}/#{source.id}/badges", master), + post api("/#{source_type.pluralize}/#{source.id}/badges", maintainer), link_url: example_url expect(response).to have_gitlab_http_status(400) end it 'returns 400 when image_url is not given' do - post api("/#{source_type.pluralize}/#{source.id}/badges", master), + post api("/#{source_type.pluralize}/#{source.id}/badges", maintainer), image_url: example_url2 expect(response).to have_gitlab_http_status(400) end it 'returns 400 when link_url or image_url is not valid' do - post api("/#{source_type.pluralize}/#{source.id}/badges", master), + post api("/#{source_type.pluralize}/#{source.id}/badges", maintainer), link_url: 'whatever', image_url: 'whatever' expect(response).to have_gitlab_http_status(400) @@ -192,9 +192,9 @@ describe API::Badges do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'updates the member' do - put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master), + put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer), link_url: example_url, image_url: example_url2 expect(response).to have_gitlab_http_status(200) @@ -205,7 +205,7 @@ describe API::Badges do end it 'returns 400 when link_url or image_url is not valid' do - put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master), + put api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer), link_url: 'whatever', image_url: 'whatever' expect(response).to have_gitlab_http_status(400) @@ -239,22 +239,22 @@ describe API::Badges do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'deletes the badge' do expect do - delete api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master) + delete api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer) expect(response).to have_gitlab_http_status(204) end.to change { source.badges.count }.by(-1) end it_behaves_like '412 response' do - let(:request) { api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", master) } + let(:request) { api("/#{source_type.pluralize}/#{source.id}/badges/#{badge.id}", maintainer) } end end it 'returns 404 if badge does not exist' do - delete api("/#{source_type.pluralize}/#{source.id}/badges/123", master) + delete api("/#{source_type.pluralize}/#{source.id}/badges/123", maintainer) expect(response).to have_gitlab_http_status(404) end @@ -289,9 +289,9 @@ describe API::Badges do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'gets the rendered badge values' do - get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}&image_url=#{example_url2}", master) + get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}&image_url=#{example_url2}", maintainer) expect(response).to have_gitlab_http_status(200) @@ -304,19 +304,19 @@ describe API::Badges do end it 'returns 400 when link_url is not given' do - get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}", master) + get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=#{example_url}", maintainer) expect(response).to have_gitlab_http_status(400) end it 'returns 400 when image_url is not given' do - get api("/#{source_type.pluralize}/#{source.id}/badges/render?image_url=#{example_url}", master) + get api("/#{source_type.pluralize}/#{source.id}/badges/render?image_url=#{example_url}", maintainer) expect(response).to have_gitlab_http_status(400) end it 'returns 400 when link_url or image_url is not valid' do - get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=whatever&image_url=whatever", master) + get api("/#{source_type.pluralize}/#{source.id}/badges/render?link_url=whatever&image_url=whatever", maintainer) expect(response).to have_gitlab_http_status(400) end @@ -326,7 +326,7 @@ describe API::Badges do context 'when deleting a badge' do context 'and the source is a project' do it 'cannot delete badges owned by the project group' do - delete api("/projects/#{project.id}/badges/#{project_group.badges.first.id}", master) + delete api("/projects/#{project.id}/badges/#{project_group.badges.first.id}", maintainer) expect(response).to have_gitlab_http_status(403) end @@ -345,9 +345,9 @@ describe API::Badges do end def setup_project - create(:project, :public, :access_requestable, creator_id: master.id, namespace: project_group) do |project| + create(:project, :public, :access_requestable, creator_id: maintainer.id, namespace: project_group) do |project| project.add_developer(developer) - project.add_master(master) + project.add_maintainer(maintainer) project.request_access(access_requester) project.project_badges << build(:project_badge, project: project) project.project_badges << build(:project_badge, project: project) @@ -358,7 +358,7 @@ describe API::Badges do def setup_group create(:group, :public, :access_requestable) do |group| group.add_developer(developer) - group.add_owner(master) + group.add_owner(maintainer) group.request_access(access_requester) group.badges << build(:group_badge, group: group) group.badges << build(:group_badge, group: group) diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index 9bb6ed62393..7fff0a6cce6 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -13,7 +13,7 @@ describe API::Branches do let(:current_user) { nil } before do - project.add_master(user) + project.add_maintainer(user) end describe "GET /projects/:id/repository/branches" do @@ -75,7 +75,7 @@ describe API::Branches do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository branches' @@ -170,7 +170,7 @@ describe API::Branches do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository branch' @@ -324,7 +324,7 @@ describe API::Branches do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } context "when a protected branch doesn't already exist" do @@ -381,8 +381,8 @@ describe API::Branches do expect(json_response['protected']).to eq(true) expect(json_response['developers_can_push']).to eq(false) expect(json_response['developers_can_merge']).to eq(false) - expect(protected_branch.reload.push_access_levels.first.access_level).to eq(Gitlab::Access::MASTER) - expect(protected_branch.reload.merge_access_levels.first.access_level).to eq(Gitlab::Access::MASTER) + expect(protected_branch.reload.push_access_levels.first.access_level).to eq(Gitlab::Access::MAINTAINER) + expect(protected_branch.reload.merge_access_levels.first.access_level).to eq(Gitlab::Access::MAINTAINER) end end @@ -458,7 +458,7 @@ describe API::Branches do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } context "when a protected branch doesn't already exist" do @@ -534,7 +534,7 @@ describe API::Branches do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } context "when a protected branch doesn't already exist" do diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index e73d1a252f5..113703fac38 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -12,7 +12,7 @@ describe API::Commits do let(:current_user) { nil } before do - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/repository/commits' do @@ -55,7 +55,7 @@ describe API::Commits do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'project commits' @@ -667,7 +667,7 @@ describe API::Commits do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'ref commit' @@ -785,7 +785,7 @@ describe API::Commits do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'ref diff' @@ -884,7 +884,7 @@ describe API::Commits do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'ref comments' diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb index 51b70fda148..61ae053cea7 100644 --- a/spec/requests/api/deployments_spec.rb +++ b/spec/requests/api/deployments_spec.rb @@ -5,7 +5,7 @@ describe API::Deployments do let(:non_member) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/deployments' do diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index fdddca5d0ef..bf93555b0f0 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -7,7 +7,7 @@ describe API::Environments do let!(:environment) { create(:environment, project: project) } before do - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/environments' do @@ -126,7 +126,7 @@ describe API::Environments do end describe 'DELETE /projects/:id/environments/:environment_id' do - context 'as a master' do + context 'as a maintainer' do it 'returns a 200 for an existing environment' do delete api("/projects/#{project.id}/environments/#{environment.id}", user) @@ -155,7 +155,7 @@ describe API::Environments do end describe 'POST /projects/:id/environments/:environment_id/stop' do - context 'as a master' do + context 'as a maintainer' do context 'with a stoppable environment' do before do environment.update(state: :available) diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb index 64fa7dc824c..f87e035c89d 100644 --- a/spec/requests/api/group_variables_spec.rb +++ b/spec/requests/api/group_variables_spec.rb @@ -9,7 +9,7 @@ describe API::GroupVariables do context 'authorized user with proper permissions' do before do - group.add_master(user) + group.add_maintainer(user) end it 'returns group variables' do @@ -42,7 +42,7 @@ describe API::GroupVariables do context 'authorized user with proper permissions' do before do - group.add_master(user) + group.add_maintainer(user) end it 'returns group variable details' do @@ -82,7 +82,7 @@ describe API::GroupVariables do let!(:variable) { create(:ci_group_variable, group: group) } before do - group.add_master(user) + group.add_maintainer(user) end it 'creates variable' do @@ -138,7 +138,7 @@ describe API::GroupVariables do context 'authorized user with proper permissions' do before do - group.add_master(user) + group.add_maintainer(user) end it 'updates variable data' do @@ -184,7 +184,7 @@ describe API::GroupVariables do context 'authorized user with proper permissions' do before do - group.add_master(user) + group.add_maintainer(user) end it 'deletes variable' do diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index da23fdd7dca..65b387a2170 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -215,7 +215,7 @@ describe API::Groups do context 'when using owned in the request' do it 'returns an array of groups the user owns' do - group1.add_master(user2) + group1.add_maintainer(user2) get api('/groups', user2), owned: true @@ -251,14 +251,22 @@ describe API::Groups do projects end + def response_project_ids(json_response, key) + json_response[key].map do |project| + project['id'].to_i + end + end + context 'when unauthenticated' do it 'returns 404 for a private group' do get api("/groups/#{group2.id}") + expect(response).to have_gitlab_http_status(404) end it 'returns 200 for a public group' do get api("/groups/#{group1.id}") + expect(response).to have_gitlab_http_status(200) end @@ -268,7 +276,7 @@ describe API::Groups do get api("/groups/#{public_group.id}") - expect(json_response['projects'].map { |p| p['id'].to_i }) + expect(response_project_ids(json_response, 'projects')) .to contain_exactly(projects[:public].id) end @@ -278,7 +286,7 @@ describe API::Groups do get api("/groups/#{group1.id}") - expect(json_response['shared_projects'].map { |p| p['id'].to_i }) + expect(response_project_ids(json_response, 'shared_projects')) .to contain_exactly(projects[:public].id) end end @@ -309,6 +317,17 @@ describe API::Groups do expect(json_response['shared_projects'][0]['id']).to eq(project.id) end + it "returns one of user1's groups without projects when with_projects option is set to false" do + project = create(:project, namespace: group2, path: 'Foo') + create(:project_group_link, project: project, group: group1) + + get api("/groups/#{group1.id}", user1), with_projects: false + + expect(response).to have_gitlab_http_status(200) + expect(json_response['projects']).to be_nil + expect(json_response['shared_projects']).to be_nil + end + it "does not return a non existing group" do get api("/groups/1328", user1) @@ -327,7 +346,7 @@ describe API::Groups do get api("/groups/#{public_group.id}", user2) - expect(json_response['projects'].map { |p| p['id'].to_i }) + expect(response_project_ids(json_response, 'projects')) .to contain_exactly(projects[:public].id, projects[:internal].id) end @@ -337,7 +356,7 @@ describe API::Groups do get api("/groups/#{group1.id}", user2) - expect(json_response['shared_projects'].map { |p| p['id'].to_i }) + expect(response_project_ids(json_response, 'shared_projects')) .to contain_exactly(projects[:public].id, projects[:internal].id) end end @@ -715,9 +734,9 @@ describe API::Groups do end end - context 'as master', :nested_groups do + context 'as maintainer', :nested_groups do before do - group2.add_master(user1) + group2.add_maintainer(user1) end it 'cannot create subgroups' do @@ -793,7 +812,7 @@ describe API::Groups do it "does not remove a group if not an owner" do user4 = create(:user) - group1.add_master(user4) + group1.add_maintainer(user4) delete api("/groups/#{group1.id}", user3) diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 95eff029f98..66eb18229fa 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1083,7 +1083,7 @@ describe API::Issues do let(:project) { merge_request.source_project } before do - project.add_master(user) + project.add_maintainer(user) end context 'resolving all discussions in a merge request' do diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 50d6f4b4d99..7d1a5c12805 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -535,12 +535,14 @@ describe API::Jobs do context 'authorized user' do context 'when trace is in ObjectStorage' do let!(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) } + let(:url) { 'http://object-storage/trace' } + let(:file_path) { expand_fixture_path('trace/sample_trace') } before do - stub_remote_trace_206 + stub_remote_url_206(url, file_path) allow_any_instance_of(JobArtifactUploader).to receive(:file_storage?) { false } - allow_any_instance_of(JobArtifactUploader).to receive(:url) { remote_trace_url } - allow_any_instance_of(JobArtifactUploader).to receive(:size) { remote_trace_size } + allow_any_instance_of(JobArtifactUploader).to receive(:url) { url } + allow_any_instance_of(JobArtifactUploader).to receive(:size) { File.size(file_path) } end it 'returns specific job trace' do @@ -643,7 +645,7 @@ describe API::Jobs do end describe 'POST /projects/:id/jobs/:job_id/erase' do - let(:role) { :master } + let(:role) { :maintainer } before do project.add_role(user, role) diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index 34cbf75f4c1..a4220f5b2be 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -7,7 +7,7 @@ describe API::Labels do let!(:priority_label) { create(:label, title: 'bug', project: project, priority: 3) } before do - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/labels' do diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index ec500838eb2..01bbe7f5ec6 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -1,15 +1,15 @@ require 'spec_helper' describe API::Members do - let(:master) { create(:user, username: 'master_user') } + let(:maintainer) { create(:user, username: 'maintainer_user') } let(:developer) { create(:user) } let(:access_requester) { create(:user) } let(:stranger) { create(:user) } let(:project) do - create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| + create(:project, :public, :access_requestable, creator_id: maintainer.id, namespace: maintainer.namespace) do |project| project.add_developer(developer) - project.add_master(master) + project.add_maintainer(maintainer) project.request_access(access_requester) end end @@ -17,7 +17,7 @@ describe API::Members do let!(:group) do create(:group, :public, :access_requestable) do |group| group.add_developer(developer) - group.add_owner(master) + group.add_owner(maintainer) group.request_access(access_requester) end end @@ -28,7 +28,7 @@ describe API::Members do let(:route) { get api("/#{source_type.pluralize}/#{source.id}/members", stranger) } end - %i[master developer access_requester stranger].each do |type| + %i[maintainer developer access_requester stranger].each do |type| context "when authenticated as a #{type}" do it 'returns 200' do user = public_send(type) @@ -39,23 +39,23 @@ describe API::Members do expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(2) - expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id] + expect(json_response.map { |u| u['id'] }).to match_array [maintainer.id, developer.id] end end end it 'avoids N+1 queries' do # Establish baseline - get api("/#{source_type.pluralize}/#{source.id}/members", master) + get api("/#{source_type.pluralize}/#{source.id}/members", maintainer) control = ActiveRecord::QueryRecorder.new do - get api("/#{source_type.pluralize}/#{source.id}/members", master) + get api("/#{source_type.pluralize}/#{source.id}/members", maintainer) end project.add_developer(create(:user)) expect do - get api("/#{source_type.pluralize}/#{source.id}/members", master) + get api("/#{source_type.pluralize}/#{source.id}/members", maintainer) end.not_to exceed_query_limit(control) end @@ -68,17 +68,17 @@ describe API::Members do expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(2) - expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id] + expect(json_response.map { |u| u['id'] }).to match_array [maintainer.id, developer.id] end it 'finds members with query string' do - get api("/#{source_type.pluralize}/#{source.id}/members", developer), query: master.username + get api("/#{source_type.pluralize}/#{source.id}/members", developer), query: maintainer.username expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.count).to eq(1) - expect(json_response.first['username']).to eq(master.username) + expect(json_response.first['username']).to eq(maintainer.username) end it 'finds all members with no query specified' do @@ -88,7 +88,7 @@ describe API::Members do expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.count).to eq(2) - expect(json_response.map { |u| u['id'] }).to match_array [master.id, developer.id] + expect(json_response.map { |u| u['id'] }).to match_array [maintainer.id, developer.id] end end end @@ -129,7 +129,7 @@ describe API::Members do it_behaves_like 'a 404 response when source is private' do let(:route) do post api("/#{source_type.pluralize}/#{source.id}/members", stranger), - user_id: access_requester.id, access_level: Member::MASTER + user_id: access_requester.id, access_level: Member::MAINTAINER end end @@ -139,7 +139,7 @@ describe API::Members do it 'returns 403' do user = public_send(type) post api("/#{source_type.pluralize}/#{source.id}/members", user), - user_id: access_requester.id, access_level: Member::MASTER + user_id: access_requester.id, access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(403) end @@ -147,24 +147,24 @@ describe API::Members do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do context 'and new member is already a requester' do it 'transforms the requester into a proper member' do expect do - post api("/#{source_type.pluralize}/#{source.id}/members", master), - user_id: access_requester.id, access_level: Member::MASTER + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), + user_id: access_requester.id, access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(201) end.to change { source.members.count }.by(1) expect(source.requesters.count).to eq(0) expect(json_response['id']).to eq(access_requester.id) - expect(json_response['access_level']).to eq(Member::MASTER) + expect(json_response['access_level']).to eq(Member::MAINTAINER) end end it 'creates a new member' do expect do - post api("/#{source_type.pluralize}/#{source.id}/members", master), + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), user_id: stranger.id, access_level: Member::DEVELOPER, expires_at: '2016-08-05' expect(response).to have_gitlab_http_status(201) @@ -176,28 +176,28 @@ describe API::Members do end it "returns 409 if member already exists" do - post api("/#{source_type.pluralize}/#{source.id}/members", master), - user_id: master.id, access_level: Member::MASTER + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), + user_id: maintainer.id, access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(409) end it 'returns 400 when user_id is not given' do - post api("/#{source_type.pluralize}/#{source.id}/members", master), - access_level: Member::MASTER + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), + access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(400) end it 'returns 400 when access_level is not given' do - post api("/#{source_type.pluralize}/#{source.id}/members", master), + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), user_id: stranger.id expect(response).to have_gitlab_http_status(400) end it 'returns 400 when access_level is not valid' do - post api("/#{source_type.pluralize}/#{source.id}/members", master), + post api("/#{source_type.pluralize}/#{source.id}/members", maintainer), user_id: stranger.id, access_level: 1234 expect(response).to have_gitlab_http_status(400) @@ -210,7 +210,7 @@ describe API::Members do it_behaves_like 'a 404 response when source is private' do let(:route) do put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", stranger), - access_level: Member::MASTER + access_level: Member::MAINTAINER end end @@ -220,7 +220,7 @@ describe API::Members do it 'returns 403' do user = public_send(type) put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user), - access_level: Member::MASTER + access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(403) end @@ -228,33 +228,33 @@ describe API::Members do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do it 'updates the member' do - put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master), - access_level: Member::MASTER, expires_at: '2016-08-05' + put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer), + access_level: Member::MAINTAINER, expires_at: '2016-08-05' expect(response).to have_gitlab_http_status(200) expect(json_response['id']).to eq(developer.id) - expect(json_response['access_level']).to eq(Member::MASTER) + expect(json_response['access_level']).to eq(Member::MAINTAINER) expect(json_response['expires_at']).to eq('2016-08-05') end end it 'returns 409 if member does not exist' do - put api("/#{source_type.pluralize}/#{source.id}/members/123", master), - access_level: Member::MASTER + put api("/#{source_type.pluralize}/#{source.id}/members/123", maintainer), + access_level: Member::MAINTAINER expect(response).to have_gitlab_http_status(404) end it 'returns 400 when access_level is not given' do - put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) + put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer) expect(response).to have_gitlab_http_status(400) end it 'returns 400 when access level is not valid' do - put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master), + put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer), access_level: 1234 expect(response).to have_gitlab_http_status(400) @@ -291,11 +291,11 @@ describe API::Members do end end - context 'when authenticated as a master/owner' do + context 'when authenticated as a maintainer/owner' do context 'and member is a requester' do it 'returns 404' do expect do - delete api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", master) + delete api("/#{source_type.pluralize}/#{source.id}/members/#{access_requester.id}", maintainer) expect(response).to have_gitlab_http_status(404) end.not_to change { source.requesters.count } @@ -304,19 +304,19 @@ describe API::Members do it 'deletes the member' do expect do - delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) + delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer) expect(response).to have_gitlab_http_status(204) end.to change { source.members.count }.by(-1) end it_behaves_like '412 response' do - let(:request) { api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", master) } + let(:request) { api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer) } end end it 'returns 404 if member does not exist' do - delete api("/#{source_type.pluralize}/#{source.id}/members/123", master) + delete api("/#{source_type.pluralize}/#{source.id}/members/123", maintainer) expect(response).to have_gitlab_http_status(404) end @@ -366,7 +366,7 @@ describe API::Members do context 'Adding owner to project' do it 'returns 403' do expect do - post api("/projects/#{project.id}/members", master), + post api("/projects/#{project.id}/members", maintainer), user_id: stranger.id, access_level: Member::OWNER expect(response).to have_gitlab_http_status(400) diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb index cb647aee70f..6530dc956cb 100644 --- a/spec/requests/api/merge_request_diffs_spec.rb +++ b/spec/requests/api/merge_request_diffs_spec.rb @@ -8,7 +8,7 @@ describe API::MergeRequestDiffs, 'MergeRequestDiffs' do before do merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/merge_requests/:merge_request_iid/versions' do diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb index 98102fcd6a7..e2000ab42e8 100644 --- a/spec/requests/api/namespaces_spec.rb +++ b/spec/requests/api/namespaces_spec.rb @@ -23,10 +23,10 @@ describe API::Namespaces do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers - expect(group_kind_json_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path', - 'parent_id', 'members_count_with_descendants') + expect(group_kind_json_response.keys).to include('id', 'kind', 'name', 'path', 'full_path', + 'parent_id', 'members_count_with_descendants') - expect(user_kind_json_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path', 'parent_id') + expect(user_kind_json_response.keys).to include('id', 'kind', 'name', 'path', 'full_path', 'parent_id') end it "admin: returns an array of all namespaces" do @@ -58,8 +58,8 @@ describe API::Namespaces do owned_group_response = json_response.find { |resource| resource['id'] == group1.id } - expect(owned_group_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path', - 'parent_id', 'members_count_with_descendants') + expect(owned_group_response.keys).to include('id', 'kind', 'name', 'path', 'full_path', + 'parent_id', 'members_count_with_descendants') end it "returns correct attributes when user cannot admin group" do @@ -69,7 +69,7 @@ describe API::Namespaces do guest_group_response = json_response.find { |resource| resource['id'] == group1.id } - expect(guest_group_response.keys).to contain_exactly('id', 'kind', 'name', 'path', 'full_path', 'parent_id') + expect(guest_group_response.keys).to include('id', 'kind', 'name', 'path', 'full_path', 'parent_id') end it "user: returns an array of namespaces" do diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index f4cf5bd0530..3fb45449c74 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -44,7 +44,7 @@ describe API::Notes do # For testing the cross-reference of a private issue in a public project let(:private_project) do create(:project, namespace: private_user.namespace) - .tap { |p| p.add_master(private_user) } + .tap { |p| p.add_maintainer(private_user) } end let(:private_issue) { create(:issue, project: private_project) } diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb index a9ccbb32666..35b6ed8d5c0 100644 --- a/spec/requests/api/pages_domains_spec.rb +++ b/spec/requests/api/pages_domains_spec.rb @@ -80,7 +80,7 @@ describe API::PagesDomains do context 'when pages is disabled' do before do allow(Gitlab.config.pages).to receive(:enabled).and_return(false) - project.add_master(user) + project.add_maintainer(user) end it_behaves_like '404 response' do @@ -88,9 +88,9 @@ describe API::PagesDomains do end end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'get pages domains' @@ -177,7 +177,7 @@ describe API::PagesDomains do context 'when domain is vacant' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like '404 response' do @@ -185,9 +185,9 @@ describe API::PagesDomains do end end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'get pages domain' @@ -270,9 +270,9 @@ describe API::PagesDomains do end end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'post pages domains' @@ -380,7 +380,7 @@ describe API::PagesDomains do context 'when domain is vacant' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like '404 response' do @@ -388,9 +388,9 @@ describe API::PagesDomains do end end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'put pages domain' @@ -444,7 +444,7 @@ describe API::PagesDomains do context 'when domain is vacant' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like '404 response' do @@ -452,9 +452,9 @@ describe API::PagesDomains do end end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'delete pages domain' diff --git a/spec/requests/api/pipeline_schedules_spec.rb b/spec/requests/api/pipeline_schedules_spec.rb index 173f2a0dea0..997d413eb4f 100644 --- a/spec/requests/api/pipeline_schedules_spec.rb +++ b/spec/requests/api/pipeline_schedules_spec.rb @@ -270,38 +270,38 @@ describe API::PipelineSchedules do end describe 'DELETE /projects/:id/pipeline_schedules/:pipeline_schedule_id' do - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let!(:pipeline_schedule) do create(:ci_pipeline_schedule, project: project, owner: developer) end before do - project.add_master(master) + project.add_maintainer(maintainer) end context 'authenticated user with valid permissions' do it 'deletes pipeline_schedule' do expect do - delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}", master) + delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}", maintainer) end.to change { project.pipeline_schedules.count }.by(-1) expect(response).to have_gitlab_http_status(204) end it 'responds with 404 Not Found if requesting non-existing pipeline_schedule' do - delete api("/projects/#{project.id}/pipeline_schedules/-5", master) + delete api("/projects/#{project.id}/pipeline_schedules/-5", maintainer) expect(response).to have_gitlab_http_status(:not_found) end it_behaves_like '412 response' do - let(:request) { api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}", master) } + let(:request) { api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}", maintainer) } end end context 'authenticated user with invalid permissions' do - let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: master) } + let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: maintainer) } it 'does not delete pipeline_schedule' do delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}", developer) @@ -415,7 +415,7 @@ describe API::PipelineSchedules do end describe 'DELETE /projects/:id/pipeline_schedules/:pipeline_schedule_id/variables/:key' do - let(:master) { create(:user) } + let(:maintainer) { create(:user) } set(:pipeline_schedule) do create(:ci_pipeline_schedule, project: project, owner: developer) @@ -426,13 +426,13 @@ describe API::PipelineSchedules do end before do - project.add_master(master) + project.add_maintainer(maintainer) end context 'authenticated user with valid permissions' do it 'deletes pipeline_schedule_variable' do expect do - delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}/variables/#{pipeline_schedule_variable.key}", master) + delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}/variables/#{pipeline_schedule_variable.key}", maintainer) end.to change { Ci::PipelineScheduleVariable.count }.by(-1) expect(response).to have_gitlab_http_status(:accepted) @@ -440,14 +440,14 @@ describe API::PipelineSchedules do end it 'responds with 404 Not Found if requesting non-existing pipeline_schedule_variable' do - delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}/variables/____", master) + delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}/variables/____", maintainer) expect(response).to have_gitlab_http_status(:not_found) end end context 'authenticated user with invalid permissions' do - let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: master) } + let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: maintainer) } it 'does not delete pipeline_schedule_variable' do delete api("/projects/#{project.id}/pipeline_schedules/#{pipeline_schedule.id}/variables/#{pipeline_schedule_variable.key}", developer) diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 78ea77cb3bb..e2ca27f5d41 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -11,7 +11,7 @@ describe API::Pipelines do end before do - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/pipelines ' do diff --git a/spec/requests/api/project_export_spec.rb b/spec/requests/api/project_export_spec.rb index a4615bd081f..45e4e35d773 100644 --- a/spec/requests/api/project_export_spec.rb +++ b/spec/requests/api/project_export_spec.rb @@ -109,13 +109,13 @@ describe API::ProjectExport do it_behaves_like 'get project export status ok' end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) - project_none.add_master(user) - project_started.add_master(user) - project_finished.add_master(user) - project_after_export.add_master(user) + project.add_maintainer(user) + project_none.add_maintainer(user) + project_started.add_maintainer(user) + project_finished.add_maintainer(user) + project_after_export.add_maintainer(user) end it_behaves_like 'get project export status ok' @@ -228,13 +228,13 @@ describe API::ProjectExport do it_behaves_like 'get project download by strategy' end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) - project_none.add_master(user) - project_started.add_master(user) - project_finished.add_master(user) - project_after_export.add_master(user) + project.add_maintainer(user) + project_none.add_maintainer(user) + project_started.add_maintainer(user) + project_finished.add_maintainer(user) + project_after_export.add_maintainer(user) end it_behaves_like 'get project download by strategy' @@ -274,7 +274,7 @@ describe API::ProjectExport do stub_uploads_object_storage(ImportExportUploader) [project, project_finished, project_after_export].each do |p| - p.add_master(user) + p.add_maintainer(user) upload = ImportExportUpload.new(project: p) upload.export_file = fixture_file_upload('spec/fixtures/project_export.tar.gz', "`/tar.gz") @@ -338,13 +338,13 @@ describe API::ProjectExport do it_behaves_like 'post project export start' end - context 'when user is a master' do + context 'when user is a maintainer' do before do - project.add_master(user) - project_none.add_master(user) - project_started.add_master(user) - project_finished.add_master(user) - project_after_export.add_master(user) + project.add_maintainer(user) + project_none.add_maintainer(user) + project_started.add_maintainer(user) + project_finished.add_maintainer(user) + project_after_export.add_maintainer(user) end it_behaves_like 'post project export start' diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 12a183fed1e..bc45a63d9f1 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -13,7 +13,7 @@ describe API::ProjectHooks, 'ProjectHooks' do end before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user3) end @@ -214,7 +214,7 @@ describe API::ProjectHooks, 'ProjectHooks' do it "returns a 404 if a user attempts to delete project hooks he/she does not own" do test_user = create(:user) other_project = create(:project) - other_project.add_master(test_user) + other_project.add_maintainer(test_user) delete api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user) expect(response).to have_gitlab_http_status(404) diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb index 24b7835abf5..41243854ebc 100644 --- a/spec/requests/api/project_import_spec.rb +++ b/spec/requests/api/project_import_spec.rb @@ -146,7 +146,7 @@ describe API::ProjectImport do describe 'GET /projects/:id/import' do it 'returns the import status' do project = create(:project, :import_started) - project.add_master(user) + project.add_maintainer(user) get api("/projects/#{project.id}/import", user) @@ -156,7 +156,7 @@ describe API::ProjectImport do it 'returns the import status and the error if failed' do project = create(:project, :import_failed) - project.add_master(user) + project.add_maintainer(user) project.import_state.update(last_error: 'error') get api("/projects/#{project.id}/import", user) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index de540ba7a10..8389cb7cf9c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -40,7 +40,7 @@ describe API::Projects do create(:project_member, user: user4, project: project3, - access_level: ProjectMember::MASTER) + access_level: ProjectMember::MAINTAINER) end let(:project4) do create(:project, @@ -353,7 +353,7 @@ describe API::Projects do create(:project_member, user: user, project: project5, - access_level: ProjectMember::MASTER) + access_level: ProjectMember::MAINTAINER) end it 'returns only projects that satisfy all query parameters' do @@ -961,7 +961,7 @@ describe API::Projects do describe 'permissions' do context 'all projects' do before do - project.add_master(user) + project.add_maintainer(user) end it 'contains permission information' do @@ -969,19 +969,19 @@ describe API::Projects do expect(response).to have_gitlab_http_status(200) expect(json_response.first['permissions']['project_access']['access_level']) - .to eq(Gitlab::Access::MASTER) + .to eq(Gitlab::Access::MAINTAINER) expect(json_response.first['permissions']['group_access']).to be_nil end end context 'personal project' do it 'sets project access and returns 200' do - project.add_master(user) + project.add_maintainer(user) get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) expect(json_response['permissions']['project_access']['access_level']) - .to eq(Gitlab::Access::MASTER) + .to eq(Gitlab::Access::MAINTAINER) expect(json_response['permissions']['group_access']).to be_nil end end @@ -1526,9 +1526,23 @@ describe API::Projects do expect(response).to have_gitlab_http_status(400) end + + it 'updates avatar' do + project_param = { + avatar: fixture_file_upload('spec/fixtures/banana_sample.gif', + 'image/gif') + } + + put api("/projects/#{project3.id}", user), project_param + + expect(response).to have_gitlab_http_status(200) + expect(json_response['avatar_url']).to eq('http://localhost/uploads/'\ + '-/system/project/avatar/'\ + "#{project3.id}/banana_sample.gif") + end end - context 'when authenticated as project master' do + context 'when authenticated as project maintainer' do it 'updates path' do project_param = { path: 'bar' } put api("/projects/#{project3.id}", user4), project_param diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb index 576fde46615..69a601d7b40 100644 --- a/spec/requests/api/protected_branches_spec.rb +++ b/spec/requests/api/protected_branches_spec.rb @@ -26,9 +26,9 @@ describe API::ProtectedBranches do end end - context 'when authenticated as a master' do + context 'when authenticated as a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'protected branches' @@ -54,8 +54,8 @@ describe API::ProtectedBranches do expect(response).to have_gitlab_http_status(200) expect(json_response['name']).to eq(branch_name) - expect(json_response['push_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MASTER) - expect(json_response['merge_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MASTER) + expect(json_response['push_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MAINTAINER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MAINTAINER) end context 'when protected branch does not exist' do @@ -68,9 +68,9 @@ describe API::ProtectedBranches do end end - context 'when authenticated as a master' do + context 'when authenticated as a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it_behaves_like 'protected branch' @@ -108,9 +108,9 @@ describe API::ProtectedBranches do expect(json_response['name']).to eq(branch_name) end - context 'when authenticated as a master' do + context 'when authenticated as a maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end it 'protects a single branch' do @@ -118,8 +118,8 @@ describe API::ProtectedBranches do expect(response).to have_gitlab_http_status(201) expect(json_response['name']).to eq(branch_name) - expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) - expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) end it 'protects a single branch and developers can push' do @@ -128,7 +128,7 @@ describe API::ProtectedBranches do expect(response).to have_gitlab_http_status(201) expect(json_response['name']).to eq(branch_name) expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER) - expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) end it 'protects a single branch and developers can merge' do @@ -136,7 +136,7 @@ describe API::ProtectedBranches do expect(response).to have_gitlab_http_status(201) expect(json_response['name']).to eq(branch_name) - expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER) end @@ -155,7 +155,7 @@ describe API::ProtectedBranches do expect(response).to have_gitlab_http_status(201) expect(json_response['name']).to eq(branch_name) expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS) - expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) end it 'protects a single branch and no one can merge' do @@ -163,7 +163,7 @@ describe API::ProtectedBranches do expect(response).to have_gitlab_http_status(201) expect(json_response['name']).to eq(branch_name) - expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS) end @@ -189,8 +189,8 @@ describe API::ProtectedBranches do post post_endpoint, name: branch_name expect_protection_to_be_successful - expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) - expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER) end end @@ -225,7 +225,7 @@ describe API::ProtectedBranches do let(:delete_endpoint) { api("/projects/#{project.id}/protected_branches/#{branch_name}", user) } before do - project.add_master(user) + project.add_maintainer(user) end it "unprotects a single branch" do diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 28f8564ae92..6063afc213d 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -8,7 +8,7 @@ describe API::Repositories do let(:user) { create(:user) } let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } let!(:project) { create(:project, :repository, creator: user) } - let!(:master) { create(:project_member, :master, user: user, project: project) } + let!(:maintainer) { create(:project_member, :maintainer, user: user, project: project) } describe "GET /projects/:id/repository/tree" do let(:route) { "/projects/#{project.id}/repository/tree" } diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index b5e4b6011ea..3ebdb54f71f 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -18,8 +18,8 @@ describe API::Runners do before do # Set project access for users - create(:project_member, :master, user: user, project: project) - create(:project_member, :master, user: user, project: project2) + create(:project_member, :maintainer, user: user, project: project) + create(:project_member, :maintainer, user: user, project: project2) create(:project_member, :reporter, user: user2, project: project) end @@ -211,6 +211,69 @@ describe API::Runners do describe 'PUT /runners/:id' do context 'admin user' do + # see https://gitlab.com/gitlab-org/gitlab-ce/issues/48625 + context 'single parameter update' do + it 'runner description' do + description = shared_runner.description + update_runner(shared_runner.id, admin, description: "#{description}_updated") + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.description).to eq("#{description}_updated") + end + + it 'runner active state' do + active = shared_runner.active + update_runner(shared_runner.id, admin, active: !active) + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.active).to eq(!active) + end + + it 'runner tag list' do + update_runner(shared_runner.id, admin, tag_list: ['ruby2.1', 'pgsql', 'mysql']) + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.tag_list).to include('ruby2.1', 'pgsql', 'mysql') + end + + it 'runner untagged flag' do + # Ensure tag list is non-empty before setting untagged to false. + update_runner(shared_runner.id, admin, tag_list: ['ruby2.1', 'pgsql', 'mysql']) + update_runner(shared_runner.id, admin, run_untagged: 'false') + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.run_untagged?).to be(false) + end + + it 'runner unlocked flag' do + update_runner(shared_runner.id, admin, locked: 'true') + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.locked?).to be(true) + end + + it 'runner access level' do + update_runner(shared_runner.id, admin, access_level: 'ref_protected') + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.ref_protected?).to be_truthy + end + + it 'runner maximum timeout' do + update_runner(shared_runner.id, admin, maximum_timeout: 1234) + + expect(response).to have_gitlab_http_status(200) + expect(shared_runner.reload.maximum_timeout).to eq(1234) + end + + it 'fails with no parameters' do + put api("/runners/#{shared_runner.id}", admin) + + shared_runner.reload + expect(response).to have_gitlab_http_status(400) + end + end + context 'when runner is shared' do it 'updates runner' do description = shared_runner.description @@ -513,7 +576,7 @@ describe API::Runners do end describe 'GET /projects/:id/runners' do - context 'authorized user with master privileges' do + context 'authorized user with maintainer privileges' do it "returns project's runners" do get api("/projects/#{project.id}/runners", user) @@ -526,7 +589,7 @@ describe API::Runners do end end - context 'authorized user without master privileges' do + context 'authorized user without maintainer privileges' do it "does not return project's runners" do get api("/projects/#{project.id}/runners", user2) diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index 8df08dd1818..98f995df06f 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -10,7 +10,7 @@ describe API::Tags do let(:current_user) { nil } before do - project.add_master(user) + project.add_maintainer(user) end describe 'GET /projects/:id/repository/tags' do @@ -86,7 +86,7 @@ describe API::Tags do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository tags' @@ -168,7 +168,7 @@ describe API::Tags do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository tag' @@ -222,7 +222,7 @@ describe API::Tags do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } context "when a protected branch doesn't already exist" do @@ -341,7 +341,7 @@ describe API::Tags do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository delete tag' @@ -386,7 +386,7 @@ describe API::Tags do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository new release' @@ -452,7 +452,7 @@ describe API::Tags do end end - context 'when authenticated', 'as a master' do + context 'when authenticated', 'as a maintainer' do let(:current_user) { user } it_behaves_like 'repository update release' diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index b2c56f7af2c..0ae6796d1e4 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -6,7 +6,7 @@ describe API::Triggers do let!(:trigger_token) { 'secure_token' } let!(:trigger_token_2) { 'secure_token_2' } let!(:project) { create(:project, :repository, creator: user) } - let!(:master) { create(:project_member, :master, user: user, project: project) } + let!(:maintainer) { create(:project_member, :maintainer, user: user, project: project) } let!(:developer) { create(:project_member, :developer, user: user2, project: project) } let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token, owner: user) } let!(:trigger2) { create(:ci_trigger, project: project, token: trigger_token_2, owner: user2) } diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index 62215ea3d7d..be333df1d78 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -4,7 +4,7 @@ describe API::Variables do let(:user) { create(:user) } let(:user2) { create(:user) } let!(:project) { create(:project, creator_id: user.id) } - let!(:master) { create(:project_member, :master, user: user, project: project) } + let!(:maintainer) { create(:project_member, :maintainer, user: user, project: project) } let!(:developer) { create(:project_member, :developer, user: user2, project: project) } let!(:variable) { create(:ci_variable, project: project) } diff --git a/spec/requests/api/wikis_spec.rb b/spec/requests/api/wikis_spec.rb index 850ba696098..489cb001b82 100644 --- a/spec/requests/api/wikis_spec.rb +++ b/spec/requests/api/wikis_spec.rb @@ -7,7 +7,7 @@ require 'spec_helper' # Every state is tested for 3 user roles: # - guest # - developer -# - master +# - maintainer # because they are 3 edge cases of using wiki pages. describe API::Wikis do @@ -163,9 +163,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) get api(url, user) end @@ -193,9 +193,9 @@ describe API::Wikis do include_examples 'returns list of wiki pages' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end include_examples 'returns list of wiki pages' @@ -221,9 +221,9 @@ describe API::Wikis do include_examples 'returns list of wiki pages' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end include_examples 'returns list of wiki pages' @@ -256,9 +256,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) get api(url, user) end @@ -293,9 +293,9 @@ describe API::Wikis do end end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) get api(url, user) end @@ -337,9 +337,9 @@ describe API::Wikis do end end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) get api(url, user) end @@ -379,9 +379,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) post(api(url, user), payload) end @@ -408,9 +408,9 @@ describe API::Wikis do include_examples 'creates wiki page' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end include_examples 'creates wiki page' @@ -436,9 +436,9 @@ describe API::Wikis do include_examples 'creates wiki page' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) end include_examples 'creates wiki page' @@ -472,9 +472,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) put(api(url, user), payload) end @@ -510,9 +510,9 @@ describe API::Wikis do end end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) put(api(url, user), payload) end @@ -554,9 +554,9 @@ describe API::Wikis do end end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) put(api(url, user), payload) end @@ -607,9 +607,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) delete(api(url, user)) end @@ -639,9 +639,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) delete(api(url, user)) end @@ -671,9 +671,9 @@ describe API::Wikis do include_examples '403 Forbidden' end - context 'when user is master' do + context 'when user is maintainer' do before do - project.add_master(user) + project.add_maintainer(user) delete(api(url, user)) end diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 92fcfb65269..b030d9862c6 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -312,7 +312,7 @@ describe 'Git HTTP requests' do let(:project) { fork_project(canonical_project, nil, repository: true) } before do - canonical_project.add_master(user) + canonical_project.add_maintainer(user) create(:merge_request, source_project: project, target_project: canonical_project, @@ -398,13 +398,13 @@ describe 'Git HTTP requests' do context "when the user has access to the project" do before do - project.add_master(user) + project.add_maintainer(user) end context "when the user is blocked" do it "rejects pulls with 401 Unauthorized" do user.block - project.add_master(user) + project.add_maintainer(user) download(path, env) do |response| expect(response).to have_gitlab_http_status(:unauthorized) @@ -467,7 +467,7 @@ describe 'Git HTTP requests' do let(:path) { "#{project.full_path}.git" } before do - project.add_master(user) + project.add_maintainer(user) end context 'when username and password are provided' do @@ -827,7 +827,7 @@ describe 'Git HTTP requests' do context 'and the user is on the team' do before do - project.add_master(user) + project.add_maintainer(user) end it "responds with status 200" do @@ -850,7 +850,7 @@ describe 'Git HTTP requests' do let(:env) { { user: user.username, password: user.password } } before do - project.add_master(user) + project.add_maintainer(user) enforce_terms end diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 4d30b99262e..de39abdb746 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -63,7 +63,7 @@ describe 'Git LFS API and storage' do context 'with LFS disabled globally' do before do - project.add_master(user) + project.add_maintainer(user) allow(Gitlab.config.lfs).to receive(:enabled).and_return(false) end @@ -106,7 +106,7 @@ describe 'Git LFS API and storage' do context 'with LFS enabled globally' do before do - project.add_master(user) + project.add_maintainer(user) enable_lfs end @@ -236,7 +236,7 @@ describe 'Git LFS API and storage' do context 'and does have project access' do let(:update_permissions) do - project.add_master(user) + project.add_maintainer(user) project.lfs_objects << lfs_object end @@ -293,7 +293,7 @@ describe 'Git LFS API and storage' do context 'when user allowed' do let(:update_permissions) do - project.add_master(user) + project.add_maintainer(user) project.lfs_objects << lfs_object end @@ -829,7 +829,7 @@ describe 'Git LFS API and storage' do context 'when user is not authenticated' do context 'when user has push access' do let(:update_user_permissions) do - project.add_master(user) + project.add_maintainer(user) end it 'responds with status 401' do @@ -874,7 +874,7 @@ describe 'Git LFS API and storage' do before do allow(Gitlab::Database).to receive(:read_only?) { true } - project.add_master(user) + project.add_maintainer(user) enable_lfs end @@ -1307,7 +1307,7 @@ describe 'Git LFS API and storage' do let(:authorization) { authorize_user } before do - second_project.add_master(user) + second_project.add_maintainer(user) upstream_project.lfs_objects << lfs_object end diff --git a/spec/requests/lfs_locks_api_spec.rb b/spec/requests/lfs_locks_api_spec.rb index e44a11a7232..a44b43a591f 100644 --- a/spec/requests/lfs_locks_api_spec.rb +++ b/spec/requests/lfs_locks_api_spec.rb @@ -4,7 +4,7 @@ describe 'Git LFS File Locking API' do include WorkhorseHelpers let(:project) { create(:project) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:developer) { create(:user) } let(:guest) { create(:user) } let(:path) { 'README.md' } @@ -29,7 +29,7 @@ describe 'Git LFS File Locking API' do before do allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) - project.add_developer(master) + project.add_developer(maintainer) project.add_developer(developer) project.add_guest(guest) end @@ -99,7 +99,7 @@ describe 'Git LFS File Locking API' do include_examples 'unauthorized request' it 'returns the list of locked files grouped by owner' do - lock_file('README.md', master) + lock_file('README.md', maintainer) lock_file('README', developer) post_lfs_json url, nil, headers diff --git a/spec/serializers/deploy_key_entity_spec.rb b/spec/serializers/deploy_key_entity_spec.rb index 2bd8162d1b7..01264cf7fb5 100644 --- a/spec/serializers/deploy_key_entity_spec.rb +++ b/spec/serializers/deploy_key_entity_spec.rb @@ -44,9 +44,9 @@ describe DeployKeyEntity do it { expect(entity.as_json).to eq(expected_result) } end - describe 'returns can_edit true if user is a master of project' do + describe 'returns can_edit true if user is a maintainer of project' do before do - project.add_master(user) + project.add_maintainer(user) end it { expect(entity.as_json).to include(can_edit: true) } diff --git a/spec/serializers/environment_entity_spec.rb b/spec/serializers/environment_entity_spec.rb index 8f32c5639a1..b7324a26ed2 100644 --- a/spec/serializers/environment_entity_spec.rb +++ b/spec/serializers/environment_entity_spec.rb @@ -1,8 +1,9 @@ require 'spec_helper' describe EnvironmentEntity do + let(:request) { double('request') } let(:entity) do - described_class.new(environment, request: double) + described_class.new(environment, request: spy('request')) end let(:environment) { create(:environment) } diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index ca9b520fb38..0f0ab5ac796 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -54,7 +54,9 @@ describe EnvironmentSerializer do context 'when representing environments within folders' do let(:serializer) do - described_class.new(project: project).within_folders + described_class + .new(current_user: user, project: project) + .within_folders end let(:resource) { Environment.all } @@ -123,7 +125,8 @@ describe EnvironmentSerializer do let(:pagination) { { page: 1, per_page: 2 } } let(:serializer) do - described_class.new(project: project) + described_class + .new(current_user: user, project: project) .with_pagination(request, response) end @@ -169,7 +172,8 @@ describe EnvironmentSerializer do context 'when grouping environments within folders' do let(:serializer) do - described_class.new(project: project) + described_class + .new(current_user: user, project: project) .with_pagination(request, response) .within_folders end diff --git a/spec/serializers/group_child_entity_spec.rb b/spec/serializers/group_child_entity_spec.rb index 505a9eaac5a..dbc40bddc30 100644 --- a/spec/serializers/group_child_entity_spec.rb +++ b/spec/serializers/group_child_entity_spec.rb @@ -42,7 +42,7 @@ describe GroupChildEntity do end before do - object.add_master(user) + object.add_maintainer(user) end it 'has the correct type' do diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index fce73e0ac1f..037484931b8 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -348,7 +348,7 @@ describe Auth::ContainerRegistryAuthenticationService do end end - context 'delete authorized as master' do + context 'delete authorized as maintainer' do let(:current_project) { create(:project) } let(:current_user) { create(:user) } @@ -357,7 +357,7 @@ describe Auth::ContainerRegistryAuthenticationService do end before do - current_project.add_master(current_user) + current_project.add_maintainer(current_user) end it_behaves_like 'a valid token' diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 2b88fcc9a96..054b7b1561c 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -462,11 +462,11 @@ describe Ci::CreatePipelineService do end end - context 'when user is master' do + context 'when user is maintainer' do let(:pipeline) { execute_service } before do - project.add_master(user) + project.add_maintainer(user) end it 'creates a protected pipeline' do @@ -503,13 +503,13 @@ describe Ci::CreatePipelineService do end end - context 'when trigger belongs to a master' do + context 'when trigger belongs to a maintainer' do let(:user) { create(:user) } let(:trigger) { create(:ci_trigger, owner: user) } let(:trigger_request) { create(:ci_trigger_request, trigger: trigger) } before do - project.add_master(user) + project.add_maintainer(user) end it 'creates a pipeline' do diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 688d3b8c038..55445e71539 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -237,7 +237,7 @@ describe Ci::RetryPipelineService, '#execute' do context 'when user is not allowed to trigger manual action' do before do project.add_developer(user) - create(:protected_branch, :masters_can_push, + create(:protected_branch, :maintainers_can_push, name: pipeline.ref, project: project) end @@ -275,7 +275,7 @@ describe Ci::RetryPipelineService, '#execute' do let(:pipeline) { create(:ci_pipeline, project: forked_project, ref: 'fixes') } before do - project.add_master(user) + project.add_maintainer(user) create(:merge_request, source_project: forked_project, target_project: project, diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb index 3fc4e499b0c..cdd3d851f61 100644 --- a/spec/services/ci/stop_environments_service_spec.rb +++ b/spec/services/ci/stop_environments_service_spec.rb @@ -86,7 +86,7 @@ describe Ci::StopEnvironmentsService do context 'when user has permission to stop environments' do before do - project.add_master(user) + project.add_maintainer(user) end it 'does not stop environment' do diff --git a/spec/services/discussions/resolve_service_spec.rb b/spec/services/discussions/resolve_service_spec.rb index 3895a0b3aea..4e0d4749239 100644 --- a/spec/services/discussions/resolve_service_spec.rb +++ b/spec/services/discussions/resolve_service_spec.rb @@ -9,7 +9,7 @@ describe Discussions::ResolveService do let(:service) { described_class.new(discussion.noteable.project, user, merge_request: merge_request) } before do - project.add_master(user) + project.add_maintainer(user) end it "doesn't resolve discussions the user can't resolve" do diff --git a/spec/services/files/create_service_spec.rb b/spec/services/files/create_service_spec.rb index abe99b9e794..30d94e4318d 100644 --- a/spec/services/files/create_service_spec.rb +++ b/spec/services/files/create_service_spec.rb @@ -23,7 +23,7 @@ describe Files::CreateService do subject { described_class.new(project, user, commit_params) } before do - project.add_master(user) + project.add_maintainer(user) end describe "#execute" do diff --git a/spec/services/files/delete_service_spec.rb b/spec/services/files/delete_service_spec.rb index ace5f293097..73566afe8c8 100644 --- a/spec/services/files/delete_service_spec.rb +++ b/spec/services/files/delete_service_spec.rb @@ -37,7 +37,7 @@ describe Files::DeleteService do end before do - project.add_master(user) + project.add_maintainer(user) end describe "#execute" do diff --git a/spec/services/files/multi_service_spec.rb b/spec/services/files/multi_service_spec.rb index 59984c10990..3bdedaf3770 100644 --- a/spec/services/files/multi_service_spec.rb +++ b/spec/services/files/multi_service_spec.rb @@ -38,7 +38,7 @@ describe Files::MultiService do end before do - project.add_master(user) + project.add_maintainer(user) end describe '#execute' do diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb index eaee89fb1a5..e01fe487ffa 100644 --- a/spec/services/files/update_service_spec.rb +++ b/spec/services/files/update_service_spec.rb @@ -24,7 +24,7 @@ describe Files::UpdateService do end before do - project.add_master(user) + project.add_maintainer(user) end describe "#execute" do diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 35826de5814..3f62e7e61e1 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -11,7 +11,7 @@ describe GitPushService, services: true do let(:ref) { 'refs/heads/master' } before do - project.add_master(user) + project.add_maintainer(user) end describe 'with remote mirrors' do @@ -267,8 +267,8 @@ describe GitPushService, services: true do expect(project.default_branch).to eq("master") execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).not_to be_empty - expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) - expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) + expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) end it "when pushing a branch for the first time with default branch protection disabled" do @@ -290,7 +290,7 @@ describe GitPushService, services: true do expect(project.protected_branches).not_to be_empty expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER]) - expect(project.protected_branches.last.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_branches.last.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) end it "when pushing a branch for the first time with an existing branch permission configured" do @@ -315,7 +315,7 @@ describe GitPushService, services: true do expect(project.default_branch).to eq("master") execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).not_to be_empty - expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER]) end @@ -442,7 +442,7 @@ describe GitPushService, services: true do allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit) .and_return(closing_commit) - project.add_master(commit_author) + project.add_maintainer(commit_author) end context "to default branches" do diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index 1737fd0a9fc..48d689e11d4 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -12,7 +12,7 @@ describe Groups::UpdateService do let!(:service) { described_class.new(public_group, user, visibility_level: Gitlab::VisibilityLevel::INTERNAL) } before do - public_group.add_user(user, Gitlab::Access::MASTER) + public_group.add_user(user, Gitlab::Access::MAINTAINER) create(:project, :public, group: public_group) end @@ -26,7 +26,7 @@ describe Groups::UpdateService do let!(:service) { described_class.new(internal_group, user, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } before do - internal_group.add_user(user, Gitlab::Access::MASTER) + internal_group.add_user(user, Gitlab::Access::MAINTAINER) create(:project, :internal, group: internal_group) end @@ -55,7 +55,7 @@ describe Groups::UpdateService do context "unauthorized visibility_level validation" do let!(:service) { described_class.new(internal_group, user, visibility_level: 99) } before do - internal_group.add_user(user, Gitlab::Access::MASTER) + internal_group.add_user(user, Gitlab::Access::MAINTAINER) end it "does not change permission level" do @@ -68,7 +68,7 @@ describe Groups::UpdateService do let!(:service) { described_class.new(internal_group, user, path: SecureRandom.hex) } before do - internal_group.add_user(user, Gitlab::Access::MASTER) + internal_group.add_user(user, Gitlab::Access::MAINTAINER) create(:project, :internal, group: internal_group) end diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index 7ae49c06896..5e38d0aeb6a 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -9,7 +9,7 @@ describe Issues::CloseService do let!(:todo) { create(:todo, :assigned, user: user, project: project, target: issue, author: user2) } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) project.add_guest(guest) end diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index 79bcdc41fb0..c61c1ddcb3d 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -13,8 +13,8 @@ describe Issues::CreateService do let(:labels) { create_pair(:label, project: project) } before do - project.add_master(user) - project.add_master(assignee) + project.add_maintainer(user) + project.add_maintainer(assignee) end let(:opts) do @@ -130,7 +130,7 @@ describe Issues::CreateService do end it 'invalidates open issues counter for assignees when issue is assigned' do - project.add_master(assignee) + project.add_maintainer(assignee) described_class.new(project, user, opts).execute @@ -160,7 +160,7 @@ describe Issues::CreateService do context 'issue create service' do context 'assignees' do before do - project.add_master(user) + project.add_maintainer(user) end it 'removes assignee when user id is invalid' do @@ -180,7 +180,7 @@ describe Issues::CreateService do end it 'saves assignee when user id is valid' do - project.add_master(assignee) + project.add_maintainer(assignee) opts = { title: 'Title', description: 'Description', assignee_ids: [assignee.id] } issue = described_class.new(project, user, opts).execute @@ -224,8 +224,8 @@ describe Issues::CreateService do end before do - project.add_master(user) - project.add_master(assignee) + project.add_maintainer(user) + project.add_maintainer(assignee) end it 'assigns and sets milestone to issuable from command' do @@ -242,7 +242,7 @@ describe Issues::CreateService do let(:project) { merge_request.source_project } before do - project.add_master(user) + project.add_maintainer(user) end describe 'for a single discussion' do diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb index 42e5d544f4c..3b617d4ca54 100644 --- a/spec/services/issues/reopen_service_spec.rb +++ b/spec/services/issues/reopen_service_spec.rb @@ -24,7 +24,7 @@ describe Issues::ReopenService do let(:user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) end it 'invalidates counter cache for assignees' do diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 4cbf1a52e29..fa98d05c61b 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -18,7 +18,7 @@ describe Issues::UpdateService, :mailer do end before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) project.add_developer(user3) end @@ -596,7 +596,7 @@ describe Issues::UpdateService, :mailer do context 'valid project' do before do - target_project.add_master(user) + target_project.add_maintainer(user) end it 'calls the move service with the proper issue and project' do diff --git a/spec/services/lfs/unlock_file_service_spec.rb b/spec/services/lfs/unlock_file_service_spec.rb index 948401d7bdc..539417644db 100644 --- a/spec/services/lfs/unlock_file_service_spec.rb +++ b/spec/services/lfs/unlock_file_service_spec.rb @@ -62,11 +62,11 @@ describe Lfs::UnlockFileService do context 'when forced' do let(:developer) { create(:user) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } before do project.add_developer(developer) - project.add_master(master) + project.add_maintainer(maintainer) end context 'by a regular user' do @@ -86,7 +86,7 @@ describe Lfs::UnlockFileService do end context 'by a maintainer user' do - let(:current_user) { master } + let(:current_user) { maintainer } let(:params) do { id: lock.id, force: true } diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb index 7076571b753..5c30f5b6a61 100644 --- a/spec/services/members/approve_access_request_service_spec.rb +++ b/spec/services/members/approve_access_request_service_spec.rb @@ -34,9 +34,9 @@ describe Members::ApproveAccessRequestService do context 'with a custom access level' do it 'returns a ProjectMember with the custom access level' do - member = described_class.new(current_user, access_level: Gitlab::Access::MASTER).execute(access_requester, opts) + member = described_class.new(current_user, access_level: Gitlab::Access::MAINTAINER).execute(access_requester, opts) - expect(member.access_level).to eq(Gitlab::Access::MASTER) + expect(member.access_level).to eq(Gitlab::Access::MAINTAINER) end end end @@ -97,7 +97,7 @@ describe Members::ApproveAccessRequestService do context 'when current user can approve access request to the project' do before do - project.add_master(current_user) + project.add_maintainer(current_user) group.add_owner(current_user) end diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index 1831c62d788..5c01463d757 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -6,7 +6,7 @@ describe Members::CreateService do let(:project_user) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) end it 'adds user to members' do diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index b4e9f6af43a..ef47b0a450b 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -114,7 +114,7 @@ describe Members::DestroyService do context 'when current user can destroy the given member' do before do - group_project.add_master(current_user) + group_project.add_maintainer(current_user) group.add_owner(current_user) end @@ -170,7 +170,7 @@ describe Members::DestroyService do context 'when current user can destroy the given access requester' do before do - group_project.add_master(current_user) + group_project.add_maintainer(current_user) group.add_owner(current_user) end @@ -210,7 +210,7 @@ describe Members::DestroyService do context 'when current user can destroy the given invited user' do before do - group_project.add_master(current_user) + group_project.add_maintainer(current_user) group.add_owner(current_user) end diff --git a/spec/services/members/update_service_spec.rb b/spec/services/members/update_service_spec.rb index a451272dd1f..6d19a95ffeb 100644 --- a/spec/services/members/update_service_spec.rb +++ b/spec/services/members/update_service_spec.rb @@ -8,7 +8,7 @@ describe Members::UpdateService do let(:permission) { :update } let(:member) { source.members_and_requesters.find_by!(user_id: member_user.id) } let(:params) do - { access_level: Gitlab::Access::MASTER } + { access_level: Gitlab::Access::MAINTAINER } end shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do @@ -23,7 +23,7 @@ describe Members::UpdateService do updated_member = described_class.new(current_user, params).execute(member, permission: permission) expect(updated_member).to be_valid - expect(updated_member.access_level).to eq(Gitlab::Access::MASTER) + expect(updated_member.access_level).to eq(Gitlab::Access::MAINTAINER) end end @@ -44,7 +44,7 @@ describe Members::UpdateService do context 'when current user can update the given member' do before do - project.add_master(current_user) + project.add_maintainer(current_user) group.add_owner(current_user) end diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb index 216e0cd4266..433ffbd97f0 100644 --- a/spec/services/merge_requests/close_service_spec.rb +++ b/spec/services/merge_requests/close_service_spec.rb @@ -9,7 +9,7 @@ describe MergeRequests::CloseService do let!(:todo) { create(:todo, :assigned, user: user, project: project, target: merge_request, author: user2) } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) project.add_guest(guest) end diff --git a/spec/services/merge_requests/conflicts/list_service_spec.rb b/spec/services/merge_requests/conflicts/list_service_spec.rb index a5520e7373e..c81fa95e4b7 100644 --- a/spec/services/merge_requests/conflicts/list_service_spec.rb +++ b/spec/services/merge_requests/conflicts/list_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe MergeRequests::Conflicts::ListService do describe '#can_be_resolved_in_ui?' do - def create_merge_request(source_branch) - create(:merge_request, source_branch: source_branch, target_branch: 'conflict-start', merge_status: :unchecked) do |mr| + def create_merge_request(source_branch, target_branch = 'conflict-start') + create(:merge_request, source_branch: source_branch, target_branch: target_branch, merge_status: :unchecked) do |mr| mr.mark_as_unmergeable end end @@ -84,5 +84,11 @@ describe MergeRequests::Conflicts::ListService do expect(service.can_be_resolved_in_ui?).to be_falsey end + + it 'returns a falsey value when the conflict is in a submodule revision' do + merge_request = create_merge_request('update-gitlab-shell-v-6-0-3', 'update-gitlab-shell-v-6-0-1') + + expect(conflicts_service(merge_request).can_be_resolved_in_ui?).to be_falsey + end end end diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index 736a50b2c15..06fb61baf33 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -23,7 +23,7 @@ describe MergeRequests::CreateService do let(:merge_request) { service.execute } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(assignee) allow(service).to receive(:execute_hooks) end @@ -185,8 +185,8 @@ describe MergeRequests::CreateService do end before do - project.add_master(user) - project.add_master(assignee) + project.add_maintainer(user) + project.add_maintainer(assignee) end it 'assigns and sets milestone to issuable from command' do @@ -202,7 +202,7 @@ describe MergeRequests::CreateService do let(:assignee) { create(:user) } before do - project.add_master(user) + project.add_maintainer(user) end it 'removes assignee_id when user id is invalid' do @@ -222,7 +222,7 @@ describe MergeRequests::CreateService do end it 'saves assignee when user id is valid' do - project.add_master(assignee) + project.add_maintainer(assignee) opts = { title: 'Title', description: 'Description', assignee_id: assignee.id } merge_request = described_class.new(project, user, opts).execute @@ -242,7 +242,7 @@ describe MergeRequests::CreateService do end it 'invalidates open merge request counter for assignees when merge request is assigned' do - project.add_master(assignee) + project.add_maintainer(assignee) described_class.new(project, user, opts).execute @@ -286,7 +286,7 @@ describe MergeRequests::CreateService do end before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(assignee) end @@ -316,7 +316,7 @@ describe MergeRequests::CreateService do context 'when user can not access source project' do before do target_project.add_developer(assignee) - target_project.add_master(user) + target_project.add_maintainer(user) end it 'raises an error' do @@ -328,7 +328,7 @@ describe MergeRequests::CreateService do context 'when user can not access target project' do before do target_project.add_developer(assignee) - target_project.add_master(user) + target_project.add_maintainer(user) end it 'raises an error' do @@ -372,7 +372,7 @@ describe MergeRequests::CreateService do before do project.add_developer(assignee) - project.add_master(user) + project.add_maintainer(user) end it 'ignores source_project_id' do diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb index 28f56d19657..fe673de46aa 100644 --- a/spec/services/merge_requests/ff_merge_service_spec.rb +++ b/spec/services/merge_requests/ff_merge_service_spec.rb @@ -13,7 +13,7 @@ describe MergeRequests::FfMergeService do let(:project) { merge_request.project } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) end diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 33eea2cf5c3..9dd235f6660 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -7,7 +7,7 @@ describe MergeRequests::MergeService do let(:project) { merge_request.project } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) end diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb index 46e4e3559dc..ba2b062875b 100644 --- a/spec/services/merge_requests/post_merge_service_spec.rb +++ b/spec/services/merge_requests/post_merge_service_spec.rb @@ -6,7 +6,7 @@ describe MergeRequests::PostMergeService do let(:project) { merge_request.project } before do - project.add_master(user) + project.add_maintainer(user) end describe '#execute' do diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb index 4daa25f8cf2..2703da7ae44 100644 --- a/spec/services/merge_requests/rebase_service_spec.rb +++ b/spec/services/merge_requests/rebase_service_spec.rb @@ -15,7 +15,7 @@ describe MergeRequests::RebaseService do subject(:service) { described_class.new(project, user, {}) } before do - project.add_master(user) + project.add_maintainer(user) end describe '#execute' do diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb index 9ee37c51d95..e10eaa95da4 100644 --- a/spec/services/merge_requests/reopen_service_spec.rb +++ b/spec/services/merge_requests/reopen_service_spec.rb @@ -8,7 +8,7 @@ describe MergeRequests::ReopenService do let(:project) { merge_request.project } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) project.add_guest(guest) end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 443dcd92a8b..f0029af83cc 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -19,7 +19,7 @@ describe MergeRequests::UpdateService, :mailer do end before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) project.add_developer(user3) end diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb index adad73f7e11..3f7a544ea0a 100644 --- a/spec/services/milestones/close_service_spec.rb +++ b/spec/services/milestones/close_service_spec.rb @@ -6,7 +6,7 @@ describe Milestones::CloseService do let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) } before do - project.add_master(user) + project.add_maintainer(user) end describe '#execute' do diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb index f2a18c7295a..0c91112026f 100644 --- a/spec/services/milestones/create_service_spec.rb +++ b/spec/services/milestones/create_service_spec.rb @@ -7,7 +7,7 @@ describe Milestones::CreateService do describe '#execute' do context "valid params" do before do - project.add_master(user) + project.add_maintainer(user) opts = { title: 'v2.1.9', diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index 9703780b0e9..6f3612501f4 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -8,7 +8,7 @@ describe Milestones::DestroyService do let!(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) } before do - project.add_master(user) + project.add_maintainer(user) end def service diff --git a/spec/services/milestones/promote_service_spec.rb b/spec/services/milestones/promote_service_spec.rb index a0a2843b676..df212d912e9 100644 --- a/spec/services/milestones/promote_service_spec.rb +++ b/spec/services/milestones/promote_service_spec.rb @@ -10,7 +10,7 @@ describe Milestones::PromoteService do describe '#execute' do before do - group.add_master(user) + group.add_maintainer(user) end context 'validations' do diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 2b2b983494f..0fd37c95e42 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -10,7 +10,7 @@ describe Notes::CreateService do describe '#execute' do before do - project.add_master(user) + project.add_maintainer(user) end context "valid params" do diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb index 4e2ab919f0f..5aae0d711c3 100644 --- a/spec/services/notes/post_process_service_spec.rb +++ b/spec/services/notes/post_process_service_spec.rb @@ -7,7 +7,7 @@ describe Notes::PostProcessService do describe '#execute' do before do - project.add_master(user) + project.add_maintainer(user) note_opts = { note: 'Awesome comment', noteable_type: 'Issue', diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index b1e218821d2..784dac55454 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe Notes::QuickActionsService do shared_context 'note on noteable' do let(:project) { create(:project) } - let(:master) { create(:user).tap { |u| project.add_master(u) } } + let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } let(:assignee) { create(:user) } before do - project.add_master(assignee) + project.add_maintainer(assignee) end end @@ -184,7 +184,7 @@ describe Notes::QuickActionsService do include_context 'note on noteable' it 'delegates to the class method' do - service = described_class.new(project, master) + service = described_class.new(project, maintainer) note = create(:note_on_issue, project: project) expect(described_class).to receive(:supported?).with(note) @@ -194,7 +194,7 @@ describe Notes::QuickActionsService do end describe '#execute' do - let(:service) { described_class.new(project, master) } + let(:service) { described_class.new(project, maintainer) } it_behaves_like 'note on noteable that supports quick actions' do let(:note) { build(:note_on_issue, project: project) } @@ -212,19 +212,19 @@ describe Notes::QuickActionsService do context 'CE restriction for issue assignees' do describe '/assign' do let(:project) { create(:project) } - let(:master) { create(:user).tap { |u| project.add_master(u) } } + let(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } } let(:assignee) { create(:user) } - let(:master) { create(:user) } - let(:service) { described_class.new(project, master) } + let(:maintainer) { create(:user) } + let(:service) { described_class.new(project, maintainer) } let(:note) { create(:note_on_issue, note: note_text, project: project) } let(:note_text) do - %(/assign @#{assignee.username} @#{master.username}\n") + %(/assign @#{assignee.username} @#{maintainer.username}\n") end before do - project.add_master(master) - project.add_master(assignee) + project.add_maintainer(maintainer) + project.add_maintainer(assignee) end it 'adds only one assignee from the list' do diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb index 65b1d613998..533dcdcd6cd 100644 --- a/spec/services/notes/update_service_spec.rb +++ b/spec/services/notes/update_service_spec.rb @@ -9,7 +9,7 @@ describe Notes::UpdateService do let(:note) { create(:note, project: project, noteable: issue, author: user, note: "Old note #{user2.to_reference}") } before do - project.add_master(user) + project.add_maintainer(user) project.add_developer(user2) project.add_developer(user3) end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index ab91176737d..c442f6fe32f 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -172,9 +172,9 @@ describe NotificationService, :mailer do before do build_team(note.project) - project.add_master(issue.author) - project.add_master(assignee) - project.add_master(note.author) + project.add_maintainer(issue.author) + project.add_maintainer(assignee) + project.add_maintainer(note.author) @u_custom_off = create_user_with_notification(:custom, 'custom_off') project.add_guest(@u_custom_off) @@ -255,8 +255,8 @@ describe NotificationService, :mailer do describe 'new note on issue in project that belongs to a group' do before do note.project.namespace_id = group.id - group.add_user(@u_watcher, GroupMember::MASTER) - group.add_user(@u_custom_global, GroupMember::MASTER) + group.add_user(@u_watcher, GroupMember::MAINTAINER) + group.add_user(@u_custom_global, GroupMember::MAINTAINER) note.project.save @u_watcher.notification_settings_for(note.project).participating! @@ -373,7 +373,7 @@ describe NotificationService, :mailer do before do build_team(note.project) build_group(note.project) - note.project.add_master(note.author) + note.project.add_maintainer(note.author) add_users_with_subscription(note.project, issue) reset_delivered_emails! end @@ -436,7 +436,7 @@ describe NotificationService, :mailer do project.add_guest(@u_guest_watcher) project.add_guest(@u_guest_custom) add_member_for_parent_group(@pg_watcher, project) - note.project.add_master(note.author) + note.project.add_maintainer(note.author) reset_delivered_emails! end @@ -577,8 +577,8 @@ describe NotificationService, :mailer do before do build_team(note.project) - project.add_master(merge_request.author) - project.add_master(merge_request.assignee) + project.add_maintainer(merge_request.author) + project.add_maintainer(merge_request.assignee) end describe '#new_note' do @@ -1088,8 +1088,8 @@ describe NotificationService, :mailer do let(:merge_request) { create :merge_request, source_project: project, assignee: create(:user), description: 'cc @participant' } before do - project.add_master(merge_request.author) - project.add_master(merge_request.assignee) + project.add_maintainer(merge_request.author) + project.add_maintainer(merge_request.assignee) build_team(merge_request.target_project) add_users_with_subscription(merge_request.target_project, merge_request) update_custom_notification(:new_merge_request, @u_guest_custom, resource: project) @@ -1529,13 +1529,13 @@ describe NotificationService, :mailer do let(:added_user) { create(:user) } describe '#new_access_request' do - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:owner) { create(:user) } let(:developer) { create(:user) } let!(:group) do create(:group, :public, :access_requestable) do |group| group.add_owner(owner) - group.add_master(master) + group.add_maintainer(maintainer) group.add_developer(developer) end end @@ -1544,11 +1544,11 @@ describe NotificationService, :mailer do reset_delivered_emails! end - it 'sends notification to group owners_and_masters' do + it 'sends notification to group owners_and_maintainers' do group.request_access(added_user) should_email(owner) - should_email(master) + should_email(maintainer) should_not_email(developer) end end @@ -1601,11 +1601,11 @@ describe NotificationService, :mailer do context 'for a project in a user namespace' do let(:project) do create(:project, :public, :access_requestable) do |project| - project.add_master(project.owner) + project.add_maintainer(project.owner) end end - it 'sends notification to project owners_and_masters' do + it 'sends notification to project owners_and_maintainers' do project.request_access(added_user) should_only_email(project.owner) @@ -1621,7 +1621,7 @@ describe NotificationService, :mailer do reset_delivered_emails! end - it 'sends notification to group owners_and_masters' do + it 'sends notification to group owners_and_maintainers' do project.request_access(added_user) should_only_email(group_owner) @@ -1759,11 +1759,11 @@ describe NotificationService, :mailer do end before do - project.add_master(u_member) - project.add_master(u_watcher) - project.add_master(u_custom_notification_unset) - project.add_master(u_custom_notification_enabled) - project.add_master(u_custom_notification_disabled) + project.add_maintainer(u_member) + project.add_maintainer(u_watcher) + project.add_maintainer(u_custom_notification_unset) + project.add_maintainer(u_custom_notification_enabled) + project.add_maintainer(u_custom_notification_disabled) reset_delivered_emails! end @@ -1903,15 +1903,15 @@ describe NotificationService, :mailer do set(:u_blocked) { create(:user, :blocked) } set(:u_silence) { create_user_with_notification(:disabled, 'silent', project) } set(:u_owner) { project.owner } - set(:u_master1) { create(:user) } - set(:u_master2) { create(:user) } + set(:u_maintainer1) { create(:user) } + set(:u_maintainer2) { create(:user) } set(:u_developer) { create(:user) } before do - project.add_master(u_blocked) - project.add_master(u_silence) - project.add_master(u_master1) - project.add_master(u_master2) + project.add_maintainer(u_blocked) + project.add_maintainer(u_silence) + project.add_maintainer(u_maintainer1) + project.add_maintainer(u_maintainer2) project.add_developer(u_developer) reset_delivered_emails! @@ -1926,12 +1926,12 @@ describe NotificationService, :mailer do describe "##{sym}" do subject(:notify!) { notification.send(sym, domain) } - it 'emails current watching masters' do + it 'emails current watching maintainers' do expect(Notify).to receive(:"#{sym}_email").at_least(:once).and_call_original notify! - should_only_email(u_master1, u_master2, u_owner) + should_only_email(u_maintainer1, u_maintainer2, u_owner) end it 'emails nobody if the project is missing' do @@ -1945,26 +1945,26 @@ describe NotificationService, :mailer do end describe '#pages_domain_verification_failed' do - it 'emails current watching masters' do + it 'emails current watching maintainers' do notification.pages_domain_verification_failed(domain) - should_only_email(u_master1, u_master2, u_owner) + should_only_email(u_maintainer1, u_maintainer2, u_owner) end end describe '#pages_domain_enabled' do - it 'emails current watching masters' do + it 'emails current watching maintainers' do notification.pages_domain_enabled(domain) - should_only_email(u_master1, u_master2, u_owner) + should_only_email(u_maintainer1, u_maintainer2, u_owner) end end describe '#pages_domain_disabled' do - it 'emails current watching masters' do + it 'emails current watching maintainers' do notification.pages_domain_disabled(domain) - should_only_email(u_master1, u_master2, u_owner) + should_only_email(u_maintainer1, u_maintainer2, u_owner) end end end @@ -1988,15 +1988,15 @@ describe NotificationService, :mailer do @u_guest_watcher = create_user_with_notification(:watch, 'guest_watching') @u_guest_custom = create_user_with_notification(:custom, 'guest_custom') - project.add_master(@u_watcher) - project.add_master(@u_participating) - project.add_master(@u_participant_mentioned) - project.add_master(@u_disabled) - project.add_master(@u_mentioned) - project.add_master(@u_committer) - project.add_master(@u_not_mentioned) - project.add_master(@u_lazy_participant) - project.add_master(@u_custom_global) + project.add_maintainer(@u_watcher) + project.add_maintainer(@u_participating) + project.add_maintainer(@u_participant_mentioned) + project.add_maintainer(@u_disabled) + project.add_maintainer(@u_mentioned) + project.add_maintainer(@u_committer) + project.add_maintainer(@u_not_mentioned) + project.add_maintainer(@u_lazy_participant) + project.add_maintainer(@u_custom_global) end # Users in the project's group but not part of project's team @@ -2011,7 +2011,7 @@ describe NotificationService, :mailer do # Group member: global=watch, group=global @g_global_watcher ||= create_global_setting_for(create(:user), :watch) - group.add_users([@g_watcher, @g_global_watcher], :master) + group.add_users([@g_watcher, @g_global_watcher], :maintainer) group end @@ -2050,7 +2050,7 @@ describe NotificationService, :mailer do project.reload - project.group.parent.add_master(user) + project.group.parent.add_maintainer(user) end def should_email_nested_group_user(user, times: 1, recipients: email_recipients) @@ -2072,11 +2072,11 @@ describe NotificationService, :mailer do @subscribed_participant = create_global_setting_for(create(:user, username: 'subscribed_participant'), :participating) @watcher_and_subscriber = create_global_setting_for(create(:user), :watch) - project.add_master(@subscribed_participant) - project.add_master(@subscriber) - project.add_master(@unsubscriber) - project.add_master(@watcher_and_subscriber) - project.add_master(@unsubscribed_mentioned) + project.add_maintainer(@subscribed_participant) + project.add_maintainer(@subscriber) + project.add_maintainer(@unsubscriber) + project.add_maintainer(@watcher_and_subscriber) + project.add_maintainer(@unsubscribed_mentioned) issuable.subscriptions.create(user: @unsubscribed_mentioned, project: project, subscribed: false) issuable.subscriptions.create(user: @subscriber, project: project, subscribed: true) diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 4e4329e898e..fd69fe04053 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -23,7 +23,7 @@ describe Projects::CreateService, '#execute' do expect(project).to be_valid expect(project.owner).to eq(user) - expect(project.team.masters).to include(user) + expect(project.team.maintainers).to include(user) expect(project.namespace).to eq(user.namespace) end end @@ -47,7 +47,7 @@ describe Projects::CreateService, '#execute' do expect(project).to be_persisted expect(project.owner).to eq(user) - expect(project.team.masters).to contain_exactly(user) + expect(project.team.maintainers).to contain_exactly(user) expect(project.namespace).to eq(user.namespace) end end diff --git a/spec/services/projects/move_access_service_spec.rb b/spec/services/projects/move_access_service_spec.rb index a820ebd91f4..88d9d93c33b 100644 --- a/spec/services/projects/move_access_service_spec.rb +++ b/spec/services/projects/move_access_service_spec.rb @@ -4,18 +4,18 @@ describe Projects::MoveAccessService do let(:user) { create(:user) } let(:group) { create(:group) } let(:project_with_access) { create(:project, namespace: user.namespace) } - let(:master_user) { create(:user) } + let(:maintainer_user) { create(:user) } let(:reporter_user) { create(:user) } let(:developer_user) { create(:user) } - let(:master_group) { create(:group) } + let(:maintainer_group) { create(:group) } let(:reporter_group) { create(:group) } let(:developer_group) { create(:group) } before do - project_with_access.add_master(master_user) + project_with_access.add_maintainer(maintainer_user) project_with_access.add_developer(developer_user) project_with_access.add_reporter(reporter_user) - project_with_access.project_group_links.create(group: master_group, group_access: Gitlab::Access::MASTER) + project_with_access.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER) project_with_access.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER) project_with_access.project_group_links.create(group: reporter_group, group_access: Gitlab::Access::REPORTER) end @@ -87,7 +87,7 @@ describe Projects::MoveAccessService do let(:options) { { remove_remaining_elements: false } } it 'does not remove remaining memberships' do - target_project.add_master(master_user) + target_project.add_maintainer(maintainer_user) subject.execute(project_with_access, options) @@ -95,7 +95,7 @@ describe Projects::MoveAccessService do end it 'does not remove remaining group links' do - target_project.project_group_links.create(group: master_group, group_access: Gitlab::Access::MASTER) + target_project.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER) subject.execute(project_with_access, options) diff --git a/spec/services/projects/move_project_authorizations_service_spec.rb b/spec/services/projects/move_project_authorizations_service_spec.rb index f7262b9b887..b4408393624 100644 --- a/spec/services/projects/move_project_authorizations_service_spec.rb +++ b/spec/services/projects/move_project_authorizations_service_spec.rb @@ -4,7 +4,7 @@ describe Projects::MoveProjectAuthorizationsService do let!(:user) { create(:user) } let(:project_with_users) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } - let(:master_user) { create(:user) } + let(:maintainer_user) { create(:user) } let(:reporter_user) { create(:user) } let(:developer_user) { create(:user) } @@ -12,7 +12,7 @@ describe Projects::MoveProjectAuthorizationsService do describe '#execute' do before do - project_with_users.add_master(master_user) + project_with_users.add_maintainer(maintainer_user) project_with_users.add_developer(developer_user) project_with_users.add_reporter(reporter_user) end @@ -28,7 +28,7 @@ describe Projects::MoveProjectAuthorizationsService do end it 'does not move existent authorizations to the current project' do - target_project.add_master(developer_user) + target_project.add_maintainer(developer_user) target_project.add_developer(reporter_user) expect(project_with_users.authorized_users.count).to eq 4 @@ -44,7 +44,7 @@ describe Projects::MoveProjectAuthorizationsService do let(:options) { { remove_remaining_elements: false } } it 'does not remove remaining project authorizations' do - target_project.add_master(developer_user) + target_project.add_maintainer(developer_user) target_project.add_developer(reporter_user) subject.execute(project_with_users, options) diff --git a/spec/services/projects/move_project_group_links_service_spec.rb b/spec/services/projects/move_project_group_links_service_spec.rb index e3d06e6d3d7..7ca8cf304fe 100644 --- a/spec/services/projects/move_project_group_links_service_spec.rb +++ b/spec/services/projects/move_project_group_links_service_spec.rb @@ -4,7 +4,7 @@ describe Projects::MoveProjectGroupLinksService do let!(:user) { create(:user) } let(:project_with_groups) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } - let(:master_group) { create(:group) } + let(:maintainer_group) { create(:group) } let(:reporter_group) { create(:group) } let(:developer_group) { create(:group) } @@ -12,7 +12,7 @@ describe Projects::MoveProjectGroupLinksService do describe '#execute' do before do - project_with_groups.project_group_links.create(group: master_group, group_access: Gitlab::Access::MASTER) + project_with_groups.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER) project_with_groups.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER) project_with_groups.project_group_links.create(group: reporter_group, group_access: Gitlab::Access::REPORTER) end @@ -28,7 +28,7 @@ describe Projects::MoveProjectGroupLinksService do end it 'does not move existent group links in the current project' do - target_project.project_group_links.create(group: master_group, group_access: Gitlab::Access::MASTER) + target_project.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER) target_project.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER) expect(project_with_groups.project_group_links.count).to eq 3 @@ -53,7 +53,7 @@ describe Projects::MoveProjectGroupLinksService do let(:options) { { remove_remaining_elements: false } } it 'does not remove remaining project group links' do - target_project.project_group_links.create(group: master_group, group_access: Gitlab::Access::MASTER) + target_project.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER) target_project.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER) subject.execute(project_with_groups, options) diff --git a/spec/services/projects/move_project_members_service_spec.rb b/spec/services/projects/move_project_members_service_spec.rb index 9c9a2d2fde1..c8c0eac1f13 100644 --- a/spec/services/projects/move_project_members_service_spec.rb +++ b/spec/services/projects/move_project_members_service_spec.rb @@ -4,7 +4,7 @@ describe Projects::MoveProjectMembersService do let!(:user) { create(:user) } let(:project_with_users) { create(:project, namespace: user.namespace) } let(:target_project) { create(:project, namespace: user.namespace) } - let(:master_user) { create(:user) } + let(:maintainer_user) { create(:user) } let(:reporter_user) { create(:user) } let(:developer_user) { create(:user) } @@ -12,7 +12,7 @@ describe Projects::MoveProjectMembersService do describe '#execute' do before do - project_with_users.add_master(master_user) + project_with_users.add_maintainer(maintainer_user) project_with_users.add_developer(developer_user) project_with_users.add_reporter(reporter_user) end @@ -28,7 +28,7 @@ describe Projects::MoveProjectMembersService do end it 'does not move existent members to the current project' do - target_project.add_master(developer_user) + target_project.add_maintainer(developer_user) target_project.add_developer(reporter_user) expect(project_with_users.project_members.count).to eq 4 @@ -53,7 +53,7 @@ describe Projects::MoveProjectMembersService do let(:options) { { remove_remaining_elements: false } } it 'does not remove remaining project members' do - target_project.add_master(developer_user) + target_project.add_maintainer(developer_user) target_project.add_developer(reporter_user) subject.execute(project_with_users, options) diff --git a/spec/services/projects/overwrite_project_service_spec.rb b/spec/services/projects/overwrite_project_service_spec.rb index 252c61f4224..c7900629f5f 100644 --- a/spec/services/projects/overwrite_project_service_spec.rb +++ b/spec/services/projects/overwrite_project_service_spec.rb @@ -96,10 +96,10 @@ describe Projects::OverwriteProjectService do context 'when project with elements' do it_behaves_like 'overwrite actions' do - let(:master_user) { create(:user) } + let(:maintainer_user) { create(:user) } let(:reporter_user) { create(:user) } let(:developer_user) { create(:user) } - let(:master_group) { create(:group) } + let(:maintainer_group) { create(:group) } let(:reporter_group) { create(:group) } let(:developer_group) { create(:group) } @@ -107,10 +107,10 @@ describe Projects::OverwriteProjectService do create_list(:deploy_keys_project, 2, project: project_from) create_list(:notification_setting, 2, source: project_from) create_list(:users_star_project, 2, project: project_from) - project_from.project_group_links.create(group: master_group, group_access: Gitlab::Access::MASTER) + project_from.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER) project_from.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER) project_from.project_group_links.create(group: reporter_group, group_access: Gitlab::Access::REPORTER) - project_from.add_master(master_user) + project_from.add_maintainer(maintainer_user) project_from.add_developer(developer_user) project_from.add_reporter(reporter_user) end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 5100987c2fe..7e85f599afb 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -247,7 +247,7 @@ describe Projects::TransferService do let(:group_member) { create(:user) } before do - group.add_user(owner, GroupMember::MASTER) + group.add_user(owner, GroupMember::MAINTAINER) group.add_user(group_member, GroupMember::DEVELOPER) end diff --git a/spec/services/protected_branches/create_service_spec.rb b/spec/services/protected_branches/create_service_spec.rb index 786493c3577..79b744142c6 100644 --- a/spec/services/protected_branches/create_service_spec.rb +++ b/spec/services/protected_branches/create_service_spec.rb @@ -6,8 +6,8 @@ describe ProtectedBranches::CreateService do let(:params) do { name: 'master', - merge_access_levels_attributes: [{ access_level: Gitlab::Access::MASTER }], - push_access_levels_attributes: [{ access_level: Gitlab::Access::MASTER }] + merge_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }], + push_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }] } end @@ -16,8 +16,8 @@ describe ProtectedBranches::CreateService do it 'creates a new protected branch' do expect { service.execute }.to change(ProtectedBranch, :count).by(1) - expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) - expect(project.protected_branches.last.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) + expect(project.protected_branches.last.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) end context 'when user does not have permission' do diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb index c3ed95aaebf..b16acf1d36c 100644 --- a/spec/services/protected_tags/create_service_spec.rb +++ b/spec/services/protected_tags/create_service_spec.rb @@ -6,7 +6,7 @@ describe ProtectedTags::CreateService do let(:params) do { name: 'master', - create_access_levels_attributes: [{ access_level: Gitlab::Access::MASTER }] + create_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }] } end @@ -15,7 +15,7 @@ describe ProtectedTags::CreateService do it 'creates a new protected tag' do expect { service.execute }.to change(ProtectedTag, :count).by(1) - expect(project.protected_tags.last.create_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) + expect(project.protected_tags.last.create_access_levels.map(&:access_level)).to eq([Gitlab::Access::MAINTAINER]) end end end diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb index d8dba26e194..980545b8083 100644 --- a/spec/services/search/global_service_spec.rb +++ b/spec/services/search/global_service_spec.rb @@ -10,7 +10,7 @@ describe Search::GlobalService do let!(:public_project) { create(:project, :public, name: 'searchable_public_project') } before do - found_project.add_master(user) + found_project.add_maintainer(user) end describe '#execute' do diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 02de83a2df8..e5e036c7d44 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -16,7 +16,7 @@ describe SearchService do let(:public_project) { create(:project, :public, name: 'public_project') } before do - accessible_project.add_master(user) + accessible_project.add_maintainer(user) end describe '#project' do diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb index e5fde07a6eb..122b96ef216 100644 --- a/spec/services/users/refresh_authorized_projects_service_spec.rb +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -30,10 +30,10 @@ describe Users::RefreshAuthorizedProjectsService do it 'updates the authorized projects of the user' do project2 = create(:project) to_remove = user.project_authorizations - .create!(project: project2, access_level: Gitlab::Access::MASTER) + .create!(project: project2, access_level: Gitlab::Access::MAINTAINER) expect(service).to receive(:update_authorizations) - .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MASTER]]) + .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) service.execute_without_lease end @@ -45,7 +45,7 @@ describe Users::RefreshAuthorizedProjectsService do .create!(project: project, access_level: Gitlab::Access::DEVELOPER) expect(service).to receive(:update_authorizations) - .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MASTER]]) + .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) service.execute_without_lease end @@ -76,14 +76,14 @@ describe Users::RefreshAuthorizedProjectsService do it 'inserts authorizations that should be added' do user.project_authorizations.delete_all - service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MASTER]]) + service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MAINTAINER]]) authorizations = user.project_authorizations expect(authorizations.length).to eq(1) expect(authorizations[0].user_id).to eq(user.id) expect(authorizations[0].project_id).to eq(project.id) - expect(authorizations[0].access_level).to eq(Gitlab::Access::MASTER) + expect(authorizations[0].access_level).to eq(Gitlab::Access::MAINTAINER) end end @@ -99,12 +99,12 @@ describe Users::RefreshAuthorizedProjectsService do end it 'sets the values to the access levels' do - expect(hash.values).to eq([Gitlab::Access::MASTER]) + expect(hash.values).to eq([Gitlab::Access::MAINTAINER]) end context 'personal projects' do it 'includes the project with the right access level' do - expect(hash[project.id]).to eq(Gitlab::Access::MASTER) + expect(hash[project.id]).to eq(Gitlab::Access::MAINTAINER) end end @@ -139,11 +139,11 @@ describe Users::RefreshAuthorizedProjectsService do let!(:other_project) { create(:project, group: nested_group) } before do - group.add_master(user) + group.add_maintainer(user) end it 'includes the project with the right access level' do - expect(hash[other_project.id]).to eq(Gitlab::Access::MASTER) + expect(hash[other_project.id]).to eq(Gitlab::Access::MAINTAINER) end end @@ -153,7 +153,7 @@ describe Users::RefreshAuthorizedProjectsService do let!(:project_group_link) { create(:project_group_link, project: other_project, group: group, group_access: Gitlab::Access::GUEST) } before do - group.add_master(user) + group.add_maintainer(user) end it 'includes the project with the right access level' do @@ -168,7 +168,7 @@ describe Users::RefreshAuthorizedProjectsService do let!(:project_group_link) { create(:project_group_link, project: other_project, group: nested_group, group_access: Gitlab::Access::DEVELOPER) } before do - group.add_master(user) + group.add_maintainer(user) end it 'includes the project with the right access level' do @@ -194,7 +194,7 @@ describe Users::RefreshAuthorizedProjectsService do value = hash.values[0] expect(value.project_id).to eq(project.id) - expect(value.access_level).to eq(Gitlab::Access::MASTER) + expect(value.access_level).to eq(Gitlab::Access::MAINTAINER) end end @@ -219,7 +219,7 @@ describe Users::RefreshAuthorizedProjectsService do end it 'includes the access level for every row' do - expect(row.access_level).to eq(Gitlab::Access::MASTER) + expect(row.access_level).to eq(Gitlab::Access::MAINTAINER) end end end @@ -235,7 +235,7 @@ describe Users::RefreshAuthorizedProjectsService do rows = service.fresh_authorizations.to_a expect(rows.length).to eq(1) - expect(rows.first.access_level).to eq(Gitlab::Access::MASTER) + expect(rows.first.access_level).to eq(Gitlab::Access::MAINTAINER) end context 'every returned row' do @@ -246,7 +246,7 @@ describe Users::RefreshAuthorizedProjectsService do end it 'includes the access level' do - expect(row.access_level).to eq(Gitlab::Access::MASTER) + expect(row.access_level).to eq(Gitlab::Access::MAINTAINER) end end end diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb index 1bd6c25100e..9b44c532ff6 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_slash_commands_shared_examples.rb @@ -4,7 +4,7 @@ shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type| include Spec::Support::Helpers::Features::NotesHelpers - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:project) do case issuable_type when :merge_request @@ -19,9 +19,9 @@ shared_examples 'issuable record that supports quick actions in its description let(:new_url_opts) { {} } before do - project.add_master(master) + project.add_maintainer(maintainer) - gitlab_sign_in(master) + gitlab_sign_in(maintainer) end after do @@ -210,31 +210,31 @@ shared_examples 'issuable record that supports quick actions in its description expect(page).not_to have_content '/todo' expect(page).to have_content 'Commands applied' - todos = TodosFinder.new(master).execute + todos = TodosFinder.new(maintainer).execute todo = todos.first expect(todos.size).to eq 1 expect(todo).to be_pending expect(todo.target).to eq issuable - expect(todo.author).to eq master - expect(todo.user).to eq master + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer end end context "with a note marking the #{issuable_type} as done" do before do - TodoService.new.mark_todo(issuable, master) + TodoService.new.mark_todo(issuable, maintainer) end it "creates a new todo for the #{issuable_type}" do - todos = TodosFinder.new(master).execute + todos = TodosFinder.new(maintainer).execute todo = todos.first expect(todos.size).to eq 1 expect(todos.first).to be_pending expect(todo.target).to eq issuable - expect(todo.author).to eq master - expect(todo.user).to eq master + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer add_note("/done") @@ -247,31 +247,31 @@ shared_examples 'issuable record that supports quick actions in its description context "with a note subscribing to the #{issuable_type}" do it "creates a new todo for the #{issuable_type}" do - expect(issuable.subscribed?(master, project)).to be_falsy + expect(issuable.subscribed?(maintainer, project)).to be_falsy add_note("/subscribe") expect(page).not_to have_content '/subscribe' expect(page).to have_content 'Commands applied' - expect(issuable.subscribed?(master, project)).to be_truthy + expect(issuable.subscribed?(maintainer, project)).to be_truthy end end context "with a note unsubscribing to the #{issuable_type} as done" do before do - issuable.subscribe(master, project) + issuable.subscribe(maintainer, project) end it "creates a new todo for the #{issuable_type}" do - expect(issuable.subscribed?(master, project)).to be_truthy + expect(issuable.subscribed?(maintainer, project)).to be_truthy add_note("/unsubscribe") expect(page).not_to have_content '/unsubscribe' expect(page).to have_content 'Commands applied' - expect(issuable.subscribed?(master, project)).to be_falsy + expect(issuable.subscribed?(maintainer, project)).to be_falsy end end @@ -282,7 +282,7 @@ shared_examples 'issuable record that supports quick actions in its description expect(page).not_to have_content '/assign me' expect(page).to have_content 'Commands applied' - expect(issuable.reload.assignees).to eq [master] + expect(issuable.reload.assignees).to eq [maintainer] end end end diff --git a/spec/support/helpers/markdown_feature.rb b/spec/support/helpers/markdown_feature.rb index 39e94ad53de..346f5b1cc4d 100644 --- a/spec/support/helpers/markdown_feature.rb +++ b/spec/support/helpers/markdown_feature.rb @@ -24,7 +24,7 @@ class MarkdownFeature def project @project ||= create(:project, :repository, group: group).tap do |project| - project.add_master(user) + project.add_maintainer(user) end end diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 05a8e6206ae..e531495d917 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -49,7 +49,9 @@ module TestEnv 'add-pdf-file' => 'e774ebd', 'squash-large-files' => '54cec52', 'add-pdf-text-binary' => '79faa7b', - 'add_images_and_changes' => '010d106' + 'add_images_and_changes' => '010d106', + 'update-gitlab-shell-v-6-0-1' => '2f61d70', + 'update-gitlab-shell-v-6-0-3' => 'de78448' }.freeze # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily diff --git a/spec/support/http_io/http_io_helpers.rb b/spec/support/http_io/http_io_helpers.rb index 2c68c2cd9a6..42144870eb5 100644 --- a/spec/support/http_io/http_io_helpers.rb +++ b/spec/support/http_io/http_io_helpers.rb @@ -1,65 +1,49 @@ module HttpIOHelpers - def stub_remote_trace_206 - WebMock.stub_request(:get, remote_trace_url) - .to_return { |request| remote_trace_response(request, 206) } + def stub_remote_url_206(url, file_path) + WebMock.stub_request(:get, url) + .to_return { |request| remote_url_response(file_path, request, 206) } end - def stub_remote_trace_200 - WebMock.stub_request(:get, remote_trace_url) - .to_return { |request| remote_trace_response(request, 200) } + def stub_remote_url_200(url, file_path) + WebMock.stub_request(:get, url) + .to_return { |request| remote_url_response(file_path, request, 200) } end - def stub_remote_trace_500 - WebMock.stub_request(:get, remote_trace_url) + def stub_remote_url_500(url) + WebMock.stub_request(:get, url) .to_return(status: [500, "Internal Server Error"]) end - def remote_trace_url - "http://trace.com/trace" - end - - def remote_trace_response(request, responce_status) + def remote_url_response(file_path, request, response_status) range = request.headers['Range'].match(/bytes=(\d+)-(\d+)/) + body = File.read(file_path).force_encoding(Encoding::BINARY) + size = body.bytesize + { - status: responce_status, - headers: remote_trace_response_headers(responce_status, range[1].to_i, range[2].to_i), - body: range_trace_body(range[1].to_i, range[2].to_i) + status: response_status, + headers: remote_url_response_headers(response_status, range[1].to_i, range[2].to_i, size), + body: body[range[1].to_i..range[2].to_i] } end - def remote_trace_response_headers(responce_status, from, to) - headers = { 'Content-Type' => 'text/plain' } - - if responce_status == 206 - headers.merge('Content-Range' => "bytes #{from}-#{to}/#{remote_trace_size}") + def remote_url_response_headers(response_status, from, to, size) + { 'Content-Type' => 'text/plain' }.tap do |headers| + if response_status == 206 + headers.merge('Content-Range' => "bytes #{from}-#{to}/#{size}") + end end - - headers - end - - def range_trace_body(from, to) - remote_trace_body[from..to] - end - - def remote_trace_body - @remote_trace_body ||= File.read(expand_fixture_path('trace/sample_trace')) - .force_encoding(Encoding::BINARY) - end - - def remote_trace_size - remote_trace_body.bytesize end def set_smaller_buffer_size_than(file_size) blocks = (file_size / 128) new_size = (blocks / 2) * 128 - stub_const("Gitlab::Ci::Trace::HttpIO::BUFFER_SIZE", new_size) + stub_const("Gitlab::HttpIO::BUFFER_SIZE", new_size) end def set_larger_buffer_size_than(file_size) blocks = (file_size / 128) new_size = (blocks * 2) * 128 - stub_const("Gitlab::Ci::Trace::HttpIO::BUFFER_SIZE", new_size) + stub_const("Gitlab::HttpIO::BUFFER_SIZE", new_size) end end diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index 562423afc2a..4d925ac77f4 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -37,7 +37,7 @@ module ExportFileHelper event = create(:event, :created, target: milestone, project: project, author: user, action: 5) create(:push_event_payload, event: event) - create(:project_member, :master, user: user, project: project) + create(:project_member, :maintainer, user: user, project: project) create(:ci_variable, project: project) create(:ci_trigger, project: project) key = create(:deploy_key) diff --git a/spec/support/matchers/access_matchers_for_controller.rb b/spec/support/matchers/access_matchers_for_controller.rb index 42a9ed9ff34..429401a5da8 100644 --- a/spec/support/matchers/access_matchers_for_controller.rb +++ b/spec/support/matchers/access_matchers_for_controller.rb @@ -24,7 +24,7 @@ module AccessMatchersForController when User user = role sign_in(user) - when *Gitlab::Access.sym_options_with_owner.keys # owner, master, developer, reporter, guest + when *Gitlab::Access.sym_options_with_owner.keys # owner, maintainer, developer, reporter, guest raise ArgumentError, "cannot emulate #{role} without membership parent" unless membership user = create_user_by_membership(role, membership) 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 7b064162726..8b4cffaac19 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 @@ -3,7 +3,7 @@ shared_examples 'new issuable record that supports quick actions' do let!(:project) { create(:project, :repository) } - let(:user) { create(:user).tap { |u| project.add_master(u) } } + let(:user) { create(:user).tap { |u| project.add_maintainer(u) } } let(:assignee) { create(:user) } let!(:milestone) { create(:milestone, project: project) } let!(:labels) { create_list(:label, 3, project: project) } @@ -12,7 +12,7 @@ shared_examples 'new issuable record that supports quick actions' do let(:issuable) { described_class.new(project, user, params).execute } before do - project.add_master(assignee) + project.add_maintainer(assignee) end context 'with labels in command only' do diff --git a/spec/support/shared_examples/controllers/todos_shared_examples.rb b/spec/support/shared_examples/controllers/todos_shared_examples.rb deleted file mode 100644 index bafd9bac8d0..00000000000 --- a/spec/support/shared_examples/controllers/todos_shared_examples.rb +++ /dev/null @@ -1,43 +0,0 @@ -shared_examples 'todos actions' do - context 'when authorized' do - before do - sign_in(user) - parent.add_developer(user) - end - - it 'creates todo' do - expect do - post_create - end.to change { user.todos.count }.by(1) - - expect(response).to have_gitlab_http_status(200) - end - - it 'returns todo path and pending count' do - post_create - - expect(response).to have_gitlab_http_status(200) - expect(json_response['count']).to eq 1 - expect(json_response['delete_path']).to match(%r{/dashboard/todos/\d{1}}) - end - end - - context 'when not authorized for project/group' do - it 'does not create todo for resource that user has no access to' do - sign_in(user) - expect do - post_create - end.to change { user.todos.count }.by(0) - - expect(response).to have_gitlab_http_status(404) - end - - it 'does not create todo when user is not logged in' do - expect do - post_create - end.to change { user.todos.count }.by(0) - - expect(response).to have_gitlab_http_status(parent.is_a?(Group) ? 401 : 302) - end - end -end diff --git a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb index 5a569d233bc..7038a366144 100644 --- a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb +++ b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb @@ -10,9 +10,9 @@ RSpec.shared_examples 'a creatable merge request' do let!(:label2) { create(:label, project: target_project) } before do - source_project.add_master(user) - target_project.add_master(user) - target_project.add_master(user2) + source_project.add_maintainer(user) + target_project.add_maintainer(user) + target_project.add_maintainer(user2) sign_in(user) visit project_new_merge_request_path( diff --git a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb index 645db41cddc..3057845061b 100644 --- a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb +++ b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb @@ -15,9 +15,9 @@ RSpec.shared_examples 'an editable merge request' do end before do - source_project.add_master(user) - target_project.add_master(user) - target_project.add_master(user2) + source_project.add_maintainer(user) + target_project.add_maintainer(user) + target_project.add_maintainer(user2) sign_in(user) visit edit_project_merge_request_path(target_project, merge_request) diff --git a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb index b29bb3c2fc0..75ad948e42c 100644 --- a/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb +++ b/spec/support/shared_examples/features/master_manages_access_requests_shared_example.rb @@ -1,20 +1,20 @@ -RSpec.shared_examples 'Master manages access requests' do +RSpec.shared_examples 'Maintainer manages access requests' do let(:user) { create(:user) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } before do entity.request_access(user) - entity.respond_to?(:add_owner) ? entity.add_owner(master) : entity.add_master(master) - sign_in(master) + entity.respond_to?(:add_owner) ? entity.add_owner(maintainer) : entity.add_maintainer(maintainer) + sign_in(maintainer) end - it 'master can see access requests' do + it 'maintainer can see access requests' do visit members_page_path expect_visible_access_request(entity, user) end - it 'master can grant access', :js do + it 'maintainer can grant access', :js do visit members_page_path expect_visible_access_request(entity, user) @@ -28,7 +28,7 @@ RSpec.shared_examples 'Master manages access requests' do end end - it 'master can deny access', :js do + it 'maintainer can deny access', :js do visit members_page_path expect_visible_access_request(entity, user) diff --git a/spec/support/shared_examples/models/members_notifications_shared_example.rb b/spec/support/shared_examples/models/members_notifications_shared_example.rb index 76611e54306..ef5cea3f2a5 100644 --- a/spec/support/shared_examples/models/members_notifications_shared_example.rb +++ b/spec/support/shared_examples/models/members_notifications_shared_example.rb @@ -21,7 +21,7 @@ RSpec.shared_examples 'members notifications' do |entity_type| it "calls NotificationService.update_#{entity_type}_member" do expect(notification_service).to receive(:"update_#{entity_type}_member").with(member) - member.update_attribute(:access_level, Member::MASTER) + member.update_attribute(:access_level, Member::MAINTAINER) end it "does not send an email when the access level has not changed" do diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb index 79b2196660c..1b563021244 100644 --- a/spec/support/shared_examples/requests/api/notes.rb +++ b/spec/support/shared_examples/requests/api/notes.rb @@ -121,6 +121,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name| expect(json_response['body']).to eq('hi!') expect(json_response['author']['username']).to eq(user.username) expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) + expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time) end end diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb index 362f89424d4..44718ed1212 100644 --- a/spec/uploaders/gitlab_uploader_spec.rb +++ b/spec/uploaders/gitlab_uploader_spec.rb @@ -68,4 +68,66 @@ describe GitlabUploader do expect(subject.file.path).to match(/#{subject.cache_dir}/) end end + + describe '#open' do + context 'when trace is stored in File storage' do + context 'when file exists' do + let(:file) do + fixture_file_upload('spec/fixtures/trace/sample_trace', 'text/plain') + end + + before do + subject.store!(file) + end + + it 'returns io stream' do + expect(subject.open).to be_a(IO) + end + + it 'when passing block it yields' do + expect { |b| subject.open(&b) }.to yield_control + end + end + + context 'when file does not exist' do + it 'returns nil' do + expect(subject.open).to be_nil + end + + it 'when passing block it does not yield' do + expect { |b| subject.open(&b) }.not_to yield_control + end + end + end + + context 'when trace is stored in Object storage' do + before do + allow(subject).to receive(:file_storage?) { false } + end + + context 'when file exists' do + before do + allow(subject).to receive(:url) { 'http://object_storage.com/trace' } + end + + it 'returns http io stream' do + expect(subject.open).to be_a(Gitlab::HttpIO) + end + + it 'when passing block it yields' do + expect { |b| subject.open(&b) }.to yield_control.once + end + end + + context 'when file does not exist' do + it 'returns nil' do + expect(subject.open).to be_nil + end + + it 'when passing block it does not yield' do + expect { |b| subject.open(&b) }.not_to yield_control + end + end + end + end end diff --git a/spec/uploaders/job_artifact_uploader_spec.rb b/spec/uploaders/job_artifact_uploader_spec.rb index 026e4356ed6..3ad5fe7e3b3 100644 --- a/spec/uploaders/job_artifact_uploader_spec.rb +++ b/spec/uploaders/job_artifact_uploader_spec.rb @@ -23,43 +23,6 @@ describe JobArtifactUploader do store_dir: %r[\h{2}/\h{2}/\h{64}/\d{4}_\d{1,2}_\d{1,2}/\d+/\d+\z] end - describe '#open' do - subject { uploader.open } - - context 'when trace is stored in File storage' do - context 'when file exists' do - let(:file) do - fixture_file_upload('spec/fixtures/trace/sample_trace', 'text/plain') - end - - before do - uploader.store!(file) - end - - it 'returns io stream' do - is_expected.to be_a(IO) - end - end - - context 'when file does not exist' do - it 'returns nil' do - is_expected.to be_nil - end - end - end - - context 'when trace is stored in Object storage' do - before do - allow(uploader).to receive(:file_storage?) { false } - allow(uploader).to receive(:url) { 'http://object_storage.com/trace' } - end - - it 'returns http io stream' do - is_expected.to be_a(Gitlab::Ci::Trace::HttpIO) - end - end - end - context 'file is stored in valid local_path' do let(:file) do fixture_file_upload('spec/fixtures/ci_build_artifacts.zip', 'application/zip') diff --git a/spec/views/projects/imports/new.html.haml_spec.rb b/spec/views/projects/imports/new.html.haml_spec.rb index fc389641fcd..11fe144d1d2 100644 --- a/spec/views/projects/imports/new.html.haml_spec.rb +++ b/spec/views/projects/imports/new.html.haml_spec.rb @@ -9,7 +9,7 @@ describe "projects/imports/new.html.haml" do before do project.import_state.update(last_error: '<a href="http://googl.com">Foo</a>') sign_in(user) - project.add_master(user) + project.add_maintainer(user) end it "escapes HTML in import errors" do diff --git a/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb b/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb index 6e7d8db99c4..5d60d6bc5e7 100644 --- a/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb +++ b/spec/views/projects/pipeline_schedules/_pipeline_schedule.html.haml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'projects/pipeline_schedules/_pipeline_schedule' do let(:owner) { create(:user) } - let(:master) { create(:user) } + let(:maintainer) { create(:user) } let(:project) { create(:project) } let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) } @@ -17,10 +17,10 @@ describe 'projects/pipeline_schedules/_pipeline_schedule' do context 'taking ownership of schedule' do context 'when non-owner is signed in' do - let(:user) { master } + let(:user) { maintainer } before do - allow(view).to receive(:can?).with(master, :take_ownership_pipeline_schedule, pipeline_schedule).and_return(true) + allow(view).to receive(:can?).with(maintainer, :take_ownership_pipeline_schedule, pipeline_schedule).and_return(true) end it 'non-owner can take ownership of pipeline' do diff --git a/spec/views/shared/notes/_form.html.haml_spec.rb b/spec/views/shared/notes/_form.html.haml_spec.rb index 50980718e66..c57319869f3 100644 --- a/spec/views/shared/notes/_form.html.haml_spec.rb +++ b/spec/views/shared/notes/_form.html.haml_spec.rb @@ -7,7 +7,7 @@ describe 'shared/notes/_form' do let(:project) { create(:project, :repository) } before do - project.add_master(user) + project.add_maintainer(user) assign(:project, project) assign(:note, note) diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index e39dec556fc..30e67e67e0e 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -27,6 +27,12 @@ describe GitGarbageCollectWorker do subject.perform(project.id, :gc, lease_key, lease_uuid) end + + it 'handles gRPC errors' do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect).and_raise(GRPC::NotFound) + + expect { subject.perform(project.id, :gc, lease_key, lease_uuid) }.to raise_exception(Gitlab::Git::Repository::NoRepository) + end end context 'with different lease than the active one' do @@ -203,12 +209,7 @@ describe GitGarbageCollectWorker do tree: old_commit.tree, parents: [old_commit] ) - Gitlab::Git::OperationService.new(nil, project.repository.raw_repository).send( - :update_ref, - "refs/heads/#{SecureRandom.hex(6)}", - new_commit_sha, - Gitlab::Git::BLANK_SHA - ) + rugged.references.create("refs/heads/#{SecureRandom.hex(6)}", new_commit_sha) end def packs(project) diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb index c861a56497e..b57c275c770 100644 --- a/spec/workers/merge_worker_spec.rb +++ b/spec/workers/merge_worker_spec.rb @@ -8,7 +8,7 @@ describe MergeWorker do let!(:author) { merge_request.author } before do - source_project.add_master(author) + source_project.add_maintainer(author) source_project.repository.expire_branches_cache end diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb index e7a4ac0f3d6..a2fe4734d47 100644 --- a/spec/workers/pipeline_schedule_worker_spec.rb +++ b/spec/workers/pipeline_schedule_worker_spec.rb @@ -18,7 +18,7 @@ describe PipelineScheduleWorker do context 'when the schedule is runnable by the user' do before do - project.add_master(user) + project.add_maintainer(user) end context 'when there is a scheduled pipeline within next_run_at' do diff --git a/spec/workers/process_commit_worker_spec.rb b/spec/workers/process_commit_worker_spec.rb index ac79d9c0ac1..2d071c181c2 100644 --- a/spec/workers/process_commit_worker_spec.rb +++ b/spec/workers/process_commit_worker_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe ProcessCommitWorker do + include ProjectForksHelper + let(:worker) { described_class.new } let(:user) { create(:user) } let(:project) { create(:project, :public, :repository) } @@ -32,15 +34,41 @@ describe ProcessCommitWorker do worker.perform(project.id, user.id, commit.to_hash) end - context 'when commit already exists in upstream project' do - let(:forked) { create(:project, :public, :repository) } + context 'when the project is forked' do + context 'when commit already exists in the upstream project' do + it 'does not process the commit message' do + forked = fork_project(project, user, repository: true) + + expect(worker).not_to receive(:process_commit_message) + + worker.perform(forked.id, user.id, forked.commit.to_hash) + end + end + + context 'when the commit does not exist in the upstream project' do + it 'processes the commit message' do + empty_project = create(:project, :public) + forked = fork_project(empty_project, user, repository: true) + + TestEnv.copy_repo(forked, + bare_repo: TestEnv.factory_repo_path_bare, + refs: TestEnv::BRANCH_SHA) + + expect(worker).to receive(:process_commit_message) + + worker.perform(forked.id, user.id, forked.commit.to_hash) + end + end - it 'does not process commit message' do - create(:forked_project_link, forked_to_project: forked, forked_from_project: project) + context 'when the upstream project no longer exists' do + it 'processes the commit message' do + forked = fork_project(project, user, repository: true) + project.destroy! - expect(worker).not_to receive(:process_commit_message) + expect(worker).to receive(:process_commit_message) - worker.perform(forked.id, user.id, forked.commit.to_hash) + worker.perform(forked.id, user.id, forked.commit.to_hash) + end end end end |