diff options
385 files changed, 3011 insertions, 976 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml index b0794bb7434..98a497aa12a 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -9,9 +9,6 @@ plugins: - import - html settings: - html/html-extensions: - - '.html' - - '.html.raw' import/resolver: webpack: config: './config/webpack.config.js' diff --git a/.gitlab/issue_templates/Documentation.md b/.gitlab/issue_templates/Documentation.md index c0919aeeda4..67602b7b2df 100644 --- a/.gitlab/issue_templates/Documentation.md +++ b/.gitlab/issue_templates/Documentation.md @@ -9,7 +9,7 @@ * For information about documentation content and process, see https://docs.gitlab.com/ee/development/documentation/ --> -### Type of issue +<!-- Type of issue --> <!-- Un-comment the line for the applicable doc issue type to add its label. Note that all text on that line is deleted upon issue creation. --> diff --git a/.stylelintrc b/.stylelintrc index c0f21aed292..241d2c94a88 100644 --- a/.stylelintrc +++ b/.stylelintrc @@ -1,6 +1,8 @@ { "plugins":[ - "stylelint-scss" + "./scripts/frontend/stylelint/stylelint-duplicate-selectors.js", + "./scripts/frontend/stylelint/stylelint-utility-classes.js", + "stylelint-scss", ], "rules":{ "at-rule-blacklist":[ @@ -95,13 +97,15 @@ }, ], "selector-list-comma-newline-after":"always", - "selector-max-compound-selectors":[5, { "severity": "warning" }], + "selector-max-compound-selectors":[3, { "severity": "warning" }], "selector-max-id":1, "selector-no-vendor-prefix":true, "selector-pseudo-element-colon-notation":"double", "selector-pseudo-element-no-unknown":true, "shorthand-property-no-redundant-values":true, "string-quotes":"single", - "value-no-vendor-prefix":[true, { ignoreValues: ["sticky"] }] + "value-no-vendor-prefix":[true, { ignoreValues: ["sticky"] }], + "stylelint-gitlab/duplicate-selectors":[true,{ "severity": "warning" }], + "stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }], } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 74760e2ac8c..3d7e8e10280 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 11.9.1 (2019-03-25) + +### Fixed (7 changes) + +- Fix issue that caused the "Show all activity" button to appear on top of the mini pipeline status dropdown on the merge request page. !26274 +- Fix duplicated bottom match line on merge request parallel diff view. !26402 +- Allow users who can push to protected branches to create protected branches via CLI. !26413 +- Add missing .gitlab-ci.yml to Android template. !26415 +- Refresh commit count after repository head changes. !26473 +- Set proper default-branch for repository on GitHub Import. !26476 +- GitHub importer: Use the project creator to create branches from forks. !26510 + +### Changed (1 change) + +- Upgrade to Gitaly v1.27.1. !26533 + + ## 11.9.0 (2019-03-22) ### Security (24 changes) diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index aeb88715c11..3826ecd1ac1 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -8,6 +8,7 @@ import { updateTooltipTitle } from './lib/utils/common_utils'; import { isInVueNoteablePage } from './lib/utils/dom_utils'; import flash from './flash'; import axios from './lib/utils/axios_utils'; +import bp from './breakpoints'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'; @@ -264,7 +265,10 @@ export class AwardsHandler { const css = { top: `${$addBtn.offset().top + $addBtn.outerHeight()}px`, }; - if (position === 'right') { + // for xs screen we position the element on center + if (bp.getBreakpointSize() === 'xs') { + css.left = '5%'; + } else if (position === 'right') { css.left = `${$addBtn.offset().left - $menu.outerWidth() + 20}px`; $menu.addClass('is-aligned-right'); } else { diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js index fc9286d15e6..bfb073fdcdc 100644 --- a/app/assets/javascripts/behaviors/markdown/render_gfm.js +++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js @@ -4,6 +4,7 @@ import renderMath from './render_math'; import renderMermaid from './render_mermaid'; import highlightCurrentUser from './highlight_current_user'; import initUserPopovers from '../../user_popovers'; +import initMRPopovers from '../../mr_popover'; // Render GitLab flavoured Markdown // @@ -15,6 +16,7 @@ $.fn.renderGFM = function renderGFM() { renderMermaid(this.find('.js-render-mermaid')); highlightCurrentUser(this.find('.gfm-project_member').get()); initUserPopovers(this.find('.gfm-project_member').get()); + initMRPopovers(this.find('.gfm-merge_request').get()); return this; }; diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index 5b206b82fe0..d54f9ce552c 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -393,7 +393,6 @@ export default { <div slot="description" v-html="prometheusDescription"></div> </application-row> <application-row - v-if="isProjectCluster" id="runner" :logo-url="gitlabLogo" :title="applications.runner.title" @@ -409,9 +408,9 @@ export default { > <div slot="description"> {{ - s__(`ClusterIntegration|GitLab Runner connects to this - project's repository and executes CI/CD jobs, - pushing results back and deploying, + s__(`ClusterIntegration|GitLab Runner connects to the + repository and executes CI/CD jobs, + pushing results back and deploying applications to production.`) }} </div> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index caf0df8a4e3..c60246bf8ef 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -140,7 +140,7 @@ export default { :id="line.left.line_code" :class="parallelViewLeftLineType" class="line_content parallel left-side" - @mousedown.native="handleParallelLineMouseDown" + @mousedown="handleParallelLineMouseDown" v-html="line.left.rich_text" ></td> </template> @@ -171,7 +171,7 @@ export default { }, ]" class="line_content parallel right-side" - @mousedown.native="handleParallelLineMouseDown" + @mousedown="handleParallelLineMouseDown" v-html="line.right.rich_text" ></td> </template> diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index 29dc2d6a8a3..aa50fd8ff62 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -244,7 +244,7 @@ export default { <gl-loading-icon v-if="isLoading" :label="s__('GroupsTree|Loading groups')" - :size="2" + size="md" class="loading-animation prepend-top-20" /> <groups-component diff --git a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue index 2b44438f849..9161eb3d9b1 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue @@ -38,8 +38,8 @@ export default { }, }, computed: { - ...mapState('commit', ['commitAction']), - ...mapGetters('commit', ['newBranchName']), + ...mapState('commit', ['commitAction', 'newBranchName']), + ...mapGetters('commit', ['placeholderBranchName']), tooltipTitle() { return this.disabled ? this.title : ''; }, @@ -73,7 +73,8 @@ export default { </label> <div v-if="commitAction === value && showInput" class="ide-commit-new-branch"> <input - :placeholder="newBranchName" + :placeholder="placeholderBranchName" + :value="newBranchName" type="text" class="form-control monospace" @input="updateBranchName($event.target.value)" diff --git a/app/assets/javascripts/ide/stores/modules/commit/getters.js b/app/assets/javascripts/ide/stores/modules/commit/getters.js index 03777e6c10b..bbe40b2ec2f 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/getters.js +++ b/app/assets/javascripts/ide/stores/modules/commit/getters.js @@ -14,7 +14,7 @@ const createTranslatedTextForFiles = (files, text) => { export const discardDraftButtonDisabled = state => state.commitMessage === '' || state.submitCommitLoading; -export const newBranchName = (state, _, rootState) => +export const placeholderBranchName = (state, _, rootState) => `${gon.current_username}-${rootState.currentBranchId}-patch-${`${new Date().getTime()}`.substr( -BRANCH_SUFFIX_COUNT, )}`; @@ -25,7 +25,7 @@ export const branchName = (state, getters, rootState) => { state.commitAction === consts.COMMIT_TO_NEW_BRANCH_MR ) { if (state.newBranchName === '') { - return getters.newBranchName; + return getters.placeholderBranchName; } return state.newBranchName; diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue index 7076a79dd5d..b651a6e4bfb 100644 --- a/app/assets/javascripts/jobs/components/commit_block.vue +++ b/app/assets/javascripts/jobs/components/commit_block.vue @@ -39,7 +39,7 @@ export default { </gl-link> <clipboard-button - :text="commit.short_id" + :text="commit.id" :title="__('Copy commit SHA to clipboard')" css-class="btn btn-clipboard btn-transparent" /> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 895a57785bc..7883a3f9abc 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -1,4 +1,5 @@ <script> +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import Flash from '../../flash'; @@ -17,6 +18,8 @@ export default { GraphGroup, EmptyState, Icon, + GlDropdown, + GlDropdownItem, }, props: { hasMetrics: { @@ -157,28 +160,21 @@ export default { <template> <div v-if="!showEmptyState" class="prometheus-graphs prepend-top-default"> <div class="environments d-flex align-items-center"> - {{ s__('Metrics|Environment') }} - <div class="dropdown prepend-left-10"> - <button class="dropdown-menu-toggle" data-toggle="dropdown" type="button"> - <span>{{ currentEnvironmentName }}</span> - <icon name="chevron-down" /> - </button> - <div - v-if="store.environmentsData.length > 0" - class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up" + <strong>{{ s__('Metrics|Environment') }}</strong> + <gl-dropdown + class="prepend-left-10 js-environments-dropdown" + toggle-class="dropdown-menu-toggle" + :text="currentEnvironmentName" + :disabled="store.environmentsData.length === 0" + > + <gl-dropdown-item + v-for="environment in store.environmentsData" + :key="environment.id" + :active="environment.name === currentEnvironmentName" + active-class="is-active" + >{{ environment.name }}</gl-dropdown-item > - <ul> - <li v-for="environment in store.environmentsData" :key="environment.id"> - <a - :href="environment.metrics_path" - :class="{ 'is-active': environment.name == currentEnvironmentName }" - class="dropdown-item" - >{{ environment.name }}</a - > - </li> - </ul> - </div> - </div> + </gl-dropdown> </div> <graph-group v-for="(groupData, index) in store.groups" diff --git a/app/assets/javascripts/mr_popover/components/mr_popover.vue b/app/assets/javascripts/mr_popover/components/mr_popover.vue new file mode 100644 index 00000000000..8e2d8fa816a --- /dev/null +++ b/app/assets/javascripts/mr_popover/components/mr_popover.vue @@ -0,0 +1,110 @@ +<script> +import { GlPopover, GlSkeletonLoading } from '@gitlab/ui'; +import Icon from '../../vue_shared/components/icon.vue'; +import CiIcon from '../../vue_shared/components/ci_icon.vue'; +import timeagoMixin from '../../vue_shared/mixins/timeago'; +import query from '../queries/merge_request.graphql'; +import { mrStates, humanMRStates } from '../constants'; + +export default { + name: 'MRPopover', + components: { + GlPopover, + GlSkeletonLoading, + Icon, + CiIcon, + }, + mixins: [timeagoMixin], + props: { + target: { + type: HTMLAnchorElement, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + mergeRequestIID: { + type: String, + required: true, + }, + mergeRequestTitle: { + type: String, + required: true, + }, + }, + data() { + return { + mergeRequest: {}, + }; + }, + computed: { + detailedStatus() { + return this.mergeRequest.headPipeline && this.mergeRequest.headPipeline.detailedStatus; + }, + formattedTime() { + return this.timeFormated(this.mergeRequest.createdAt); + }, + statusBoxClass() { + switch (this.mergeRequest.state) { + case mrStates.merged: + return 'status-box-mr-merged'; + case mrStates.closed: + return 'status-box-closed'; + default: + return 'status-box-open'; + } + }, + stateHumanName() { + switch (this.mergeRequest.state) { + case mrStates.merged: + return humanMRStates.merged; + case mrStates.closed: + return humanMRStates.closed; + default: + return humanMRStates.open; + } + }, + showDetails() { + return Object.keys(this.mergeRequest).length > 0; + }, + }, + apollo: { + mergeRequest: { + query, + update: data => data.project.mergeRequest, + variables() { + const { projectPath, mergeRequestIID } = this; + + return { + projectPath, + mergeRequestIID, + }; + }, + }, + }, +}; +</script> + +<template> + <gl-popover :target="target" boundary="viewport" placement="top" show> + <div class="mr-popover"> + <div v-if="$apollo.loading"> + <gl-skeleton-loading :lines="1" class="animation-container-small mt-1" /> + </div> + <div v-else-if="showDetails" class="d-flex align-items-center justify-content-between"> + <div class="d-inline-flex align-items-center"> + <div :class="`issuable-status-box status-box ${statusBoxClass}`"> + {{ stateHumanName }} + </div> + <span class="text-secondary">Opened <time v-text="formattedTime"></time></span> + </div> + <ci-icon v-if="detailedStatus" :status="detailedStatus" /> + </div> + <h5 class="my-2">{{ mergeRequestTitle }}</h5> + <div class="text-secondary"> + {{ `${projectPath}!${mergeRequestIID}` }} + </div> + </div> + </gl-popover> +</template> diff --git a/app/assets/javascripts/mr_popover/constants.js b/app/assets/javascripts/mr_popover/constants.js new file mode 100644 index 00000000000..433df844c80 --- /dev/null +++ b/app/assets/javascripts/mr_popover/constants.js @@ -0,0 +1,10 @@ +export const mrStates = { + merged: 'merged', + closed: 'closed', +}; + +export const humanMRStates = { + merged: 'Merged', + closed: 'Closed', + open: 'Open', +}; diff --git a/app/assets/javascripts/mr_popover/index.js b/app/assets/javascripts/mr_popover/index.js new file mode 100644 index 00000000000..cc686b401d2 --- /dev/null +++ b/app/assets/javascripts/mr_popover/index.js @@ -0,0 +1,62 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import MRPopover from './components/mr_popover.vue'; +import createDefaultClient from '~/lib/graphql'; + +let renderedPopover; +let renderFn; + +const handleUserPopoverMouseOut = ({ target }) => { + target.removeEventListener('mouseleave', handleUserPopoverMouseOut); + + if (renderFn) { + clearTimeout(renderFn); + } + if (renderedPopover) { + renderedPopover.$destroy(); + renderedPopover = null; + } +}; + +/** + * Adds a MergeRequestPopover component to the body, hands over as much data as the target element has in data attributes. + * loads based on data-project-path and data-iid more data about an MR from the API and sets it on the popover + */ +const handleMRPopoverMount = apolloProvider => ({ target }) => { + // Add listener to actually remove it again + target.addEventListener('mouseleave', handleUserPopoverMouseOut); + + const { projectPath, mrTitle, iid } = target.dataset; + const mergeRequest = {}; + + renderFn = setTimeout(() => { + const MRPopoverComponent = Vue.extend(MRPopover); + renderedPopover = new MRPopoverComponent({ + propsData: { + target, + projectPath, + mergeRequestIID: iid, + mergeRequest, + mergeRequestTitle: mrTitle, + }, + apolloProvider, + }); + + renderedPopover.$mount(); + }, 200); // 200ms delay so not every mouseover triggers Popover + API Call +}; + +export default elements => { + const mrLinks = elements || [...document.querySelectorAll('.gfm-merge_request')]; + if (mrLinks.length > 0) { + Vue.use(VueApollo); + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), + }); + + mrLinks.forEach(el => { + el.addEventListener('mouseenter', handleMRPopoverMount(apolloProvider)); + }); + } +}; diff --git a/app/assets/javascripts/mr_popover/queries/merge_request.graphql b/app/assets/javascripts/mr_popover/queries/merge_request.graphql new file mode 100644 index 00000000000..0bb9bc03bc7 --- /dev/null +++ b/app/assets/javascripts/mr_popover/queries/merge_request.graphql @@ -0,0 +1,14 @@ +query mergeRequest($projectPath: ID!, $mergeRequestIID: ID!) { + project(fullPath: $projectPath) { + mergeRequest(iid: $mergeRequestIID) { + createdAt + state + headPipeline { + detailedStatus { + icon + group + } + } + } + } +} diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 0fabbfb06b5..a3d664a738f 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -87,13 +87,10 @@ export default { }, }, data() { - const { diff_discussion: isDiffDiscussion, resolved } = this.discussion; - return { isReplying: false, isResolving: false, resolveAsThread: true, - isRepliesCollapsed: Boolean(!isDiffDiscussion && resolved), }; }, computed: { @@ -178,11 +175,11 @@ export default { return ''; }, - shouldShowDiscussions() { - const { expanded, resolved } = this.discussion; - const isResolvedNonDiffDiscussion = !this.discussion.diff_discussion && resolved; - - return expanded || this.alwaysExpanded || isResolvedNonDiffDiscussion; + isExpanded() { + return this.discussion.expanded || this.alwaysExpanded; + }, + shouldHideDiscussionBody() { + return this.shouldRenderDiffs && !this.isExpanded; }, actionText() { const linkStart = `<a href="${_.escape(this.discussion.discussion_path)}">`; @@ -282,9 +279,6 @@ export default { toggleDiscussionHandler() { this.toggleDiscussion({ discussionId: this.discussion.id }); }, - toggleReplies() { - this.isRepliesCollapsed = !this.isRepliesCollapsed; - }, showReplyForm() { this.isReplying = true; }, @@ -405,7 +399,7 @@ Please check your network connection and try again.`; /> </div> </div> - <div v-if="shouldShowDiscussions" class="discussion-body"> + <div v-if="!shouldHideDiscussionBody" class="discussion-body"> <component :is="wrapperComponent" v-bind="wrapperComponentProps" @@ -436,11 +430,11 @@ Please check your network connection and try again.`; </component> <toggle-replies-widget v-if="hasReplies" - :collapsed="isRepliesCollapsed" + :collapsed="!isExpanded" :replies="replies" - @toggle="toggleReplies" + @toggle="toggleDiscussionHandler" /> - <template v-if="!isRepliesCollapsed"> + <template v-if="isExpanded"> <component :is="componentName(note)" v-for="note in replies" @@ -467,7 +461,7 @@ Please check your network connection and try again.`; </template> </ul> <div - v-if="!isRepliesCollapsed || !hasReplies" + v-if="isExpanded || !hasReplies" :class="{ 'is-replying': isReplying }" class="discussion-reply-holder" > diff --git a/app/assets/javascripts/vue_shared/components/ci_icon.vue b/app/assets/javascripts/vue_shared/components/ci_icon.vue index e6f0a1c69cd..25f80219993 100644 --- a/app/assets/javascripts/vue_shared/components/ci_icon.vue +++ b/app/assets/javascripts/vue_shared/components/ci_icon.vue @@ -22,6 +22,7 @@ import Icon from '../../vue_shared/components/icon.vue'; * - Jobs show view header * - Jobs show view sidebar * - Linked pipelines + * - Extended MR Popover */ const validSizes = [8, 12, 16, 18, 24, 32, 48, 72]; diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue index 7a53d053eec..216f6c62e69 100644 --- a/app/assets/javascripts/vue_shared/components/loading_button.vue +++ b/app/assets/javascripts/vue_shared/components/loading_button.vue @@ -53,7 +53,7 @@ export default { <template> <button :class="containerClass" :disabled="loading || disabled" type="button" @click="onClick"> - <transition name="fade"> + <transition name="fade-in"> <gl-loading-icon v-if="loading" :inline="true" @@ -63,7 +63,7 @@ export default { class="js-loading-button-icon" /> </transition> - <transition name="fade"> + <transition name="fade-in"> <slot> <span v-if="label" class="js-loading-button-label"> {{ label }} </span> </slot> diff --git a/app/assets/stylesheets/components/popover.scss b/app/assets/stylesheets/components/popover.scss index 2f4d30fe923..7d46b262a69 100644 --- a/app/assets/stylesheets/components/popover.scss +++ b/app/assets/stylesheets/components/popover.scss @@ -7,3 +7,10 @@ line-height: $gl-line-height; } } + +.mr-popover { + .text-secondary { + font-size: 12px; + line-height: 1.33; + } +} diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index af79a4d9392..37a729c7a63 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -61,6 +61,10 @@ border: 0; } + &.avatar-placeholder { + border: 0; + } + &:not([href]):hover { border-color: darken($gray-normal, 10%); } diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index a4af84f8d27..695ce014659 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -443,7 +443,8 @@ border-color: transparent; } - &.btn-secondary-hover-link { + &.btn-secondary-hover-link, + &.btn-default-hover-link { color: $gl-text-color-secondary; &:hover, diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 1a74e06a75d..298610a0631 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -156,6 +156,12 @@ ul.content-list { margin-top: 3px; margin-bottom: 4px; + &.btn-ldap-override { + @include media-breakpoint-up(sm) { + margin-bottom: 0; + } + } + &.has-tooltip, &:last-child { margin-right: 0; diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 6afe0d61232..de2cd600623 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -61,6 +61,10 @@ padding-top: 0; line-height: 19px; + &.btn.btn-sm { + padding: 2px 5px; + } + &:focus { margin-top: -10px; padding-top: 10px; diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss index 3a117106cff..cd3d6f8297e 100644 --- a/app/assets/stylesheets/framework/panels.scss +++ b/app/assets/stylesheets/framework/panels.scss @@ -7,7 +7,6 @@ margin-bottom: $gl-vert-padding; } - .card-header { padding: $gl-vert-padding $gl-padding; line-height: 36px; diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss index 19640ab5986..31297b9d20c 100644 --- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss +++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss @@ -181,6 +181,33 @@ margin: 0; width: 100%; } + + &.inline { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + + > .btn, + > .btn-container, + > .dropdown, + > input, + > form { + flex: 1 1 auto; + margin: 0 0 10px; + margin-left: $gl-padding-top; + width: auto; + + &:first-child { + margin-left: 0; + float: none; + } + } + + .btn-full { + flex: 1 1 100%; + margin-left: 0; + } + } } } diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index ac673eafdc7..81ccea1e01f 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -264,6 +264,16 @@ } } +.project-result { + .project-name { + font-weight: $gl-font-weight-bold; + } + + .project-path { + color: $gl-gray-400; + } +} + .user-result { min-height: 24px; display: flex; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 08dbe3d5b0f..efebbd124d0 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -23,6 +23,7 @@ $darken-border-dashed-factor: 25%; $white-light: #fff; $white-normal: #f0f0f0; $white-dark: #eaeaea; +$white-transparent: rgba(255, 255, 255, 0.8); $gray-lightest: #fdfdfd; $gray-light: #fafafa; @@ -288,6 +289,10 @@ $gl-line-height: 16px; $gl-line-height-24: 24px; $gl-line-height-14: 14px; +$system-header-height: 35px; +$issue-box-upcoming-bg: #8f8f8f; +$pages-group-name-color: #4c4e54; + /* * Common component specific colors */ @@ -410,7 +415,7 @@ $award-emoji-menu-shadow: rgba(0, 0, 0, 0.175); $award-emoji-positive-add-bg: #fed159; $award-emoji-positive-add-lines: #bb9c13; $award-emoji-width: 376px; -$award-emoji-width-xs: 300px; +$award-emoji-width-xs: 90%; /* * Search Box @@ -626,6 +631,18 @@ Animation Functions $dropdown-animation-timing: cubic-bezier(0.23, 1, 0.32, 1); /* +GitLab Plans +*/ +$gl-gold-plan: #d4af37; +$gl-silver-plan: #91a1ab; +$gl-bronze-plan: #cd7f32; + +/* +Cross-project Pipelines + */ +$linked-project-column-margin: 60px; + +/* Performance Bar */ $perf-bar-production: #222; @@ -649,6 +666,17 @@ $image-comment-cursor-left-offset: 12; $image-comment-cursor-top-offset: 12; /* +Add GitLab Slack Application +*/ +$add-to-slack-popup-max-width: 400px; +$add-to-slack-gif-max-width: 850px; +$add-to-slack-well-max-width: 750px; +$add-to-slack-logo-size: 100px; +$double-headed-arrow-width: 100px; +$double-headed-arrow-height: 25px; +$right-arrow-size: 16px; + +/* Popup */ $popup-triangle-size: 15px; diff --git a/app/assets/stylesheets/framework/vue_transitions.scss b/app/assets/stylesheets/framework/vue_transitions.scss index e07a177e153..e3bdc0b0199 100644 --- a/app/assets/stylesheets/framework/vue_transitions.scss +++ b/app/assets/stylesheets/framework/vue_transitions.scss @@ -1,9 +1,13 @@ .fade-enter-active, -.fade-leave-active { +.fade-leave-active, +.fade-in-enter-active, +.fade-out-leave-active { transition: opacity $sidebar-transition-duration $general-hover-transition-curve; } .fade-enter, +.fade-in-enter, +.fade-out-leave-to, .fade-leave-to { opacity: 0; } diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss index 161943766d4..434cbd6d21c 100644 --- a/app/assets/stylesheets/framework/wells.scss +++ b/app/assets/stylesheets/framework/wells.scss @@ -12,6 +12,10 @@ border-bottom: 1px solid $well-inner-border; } + &.borderless { + border-bottom: 0; + } + &.branch-info { .commit-sha, .commit-info { diff --git a/app/assets/stylesheets/notify.scss b/app/assets/stylesheets/notify.scss index f24c80bd81c..d77b7dfad68 100644 --- a/app/assets/stylesheets/notify.scss +++ b/app/assets/stylesheets/notify.scss @@ -1,4 +1,4 @@ -@import "framework/variables"; +@import 'framework/variables'; img { max-width: 100%; diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 8ade995525a..0a07747e0d4 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -15,6 +15,11 @@ word-wrap: nowrap; } +.content-list .group-name { + font-weight: $gl-font-weight-bold; + color: $pages-group-name-color; +} + .group-row { @include basic-list-stats; @@ -172,6 +177,50 @@ } } +.card { + .shared_runners_limit_under_quota { + color: $green-500; + } + + .shared_runners_limit_over_quota { + color: $red-500; + } +} + +.pipeline-quota { + border-top: 1px solid $table-border-color; + border-bottom: 1px solid $table-border-color; + margin: 0 0 $gl-padding; + + .row { + padding-top: 10px; + padding-bottom: 10px; + } + + .right { + text-align: right; + } + + .progress { + height: 6px; + width: 100%; + margin-bottom: 0; + margin-top: 4px; + } +} + +.user-settings-pipeline-quota { + margin-top: $gl-padding; + + .pipeline-quota { + border-top: 0; + } +} + +table.pipeline-project-metrics tr td { + padding: $gl-padding; +} + .mattermost-icon svg { width: 16px; height: 16px; diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 9f30495a7ef..c7d2369a6b8 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -145,6 +145,11 @@ ul.related-merge-requests > li { } } +.issues-footer { + padding-top: $gl-padding; + padding-bottom: 37px; +} + .issues-nav-controls { font-size: 0; diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss index eb32beb0972..e0b84e0f92d 100644 --- a/app/assets/stylesheets/pages/members.scss +++ b/app/assets/stylesheets/pages/members.scss @@ -14,6 +14,12 @@ } .member { + &.is-overriden { + .btn-ldap-override { + display: none !important; + } + } + .list-item-name { @include media-breakpoint-up(sm) { float: left; @@ -122,6 +128,49 @@ outline: 0; } +.members-ldap { + align-self: center; + height: 100%; + margin-right: 10px; + margin-left: -49px; +} + +.alert-member-ldap { + background-color: $orange-50; + + @include media-breakpoint-up(sm) { + line-height: 40px; + } + + > p { + float: left; + margin-bottom: 10px; + color: $orange-600; + + @include media-breakpoint-up(sm) { + padding-left: 55px; + margin-bottom: 0; + } + } + + .controls { + width: 100%; + + @include media-breakpoint-up(sm) { + width: auto; + } + } +} + +.btn-ldap-override { + width: 100%; + + @include media-breakpoint-up(sm) { + margin-left: 10px; + width: auto; + } +} + .flex-project-members-panel { display: flex; flex-direction: row; diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss index 3ca8e943a3a..49608a3964f 100644 --- a/app/assets/stylesheets/pages/milestone.scss +++ b/app/assets/stylesheets/pages/milestone.scss @@ -235,6 +235,7 @@ $status-box-line-height: 26px; padding: 0; } + .popover-body, .popover-content { padding: 0; } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 88984cae513..9c72dcbc54c 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -44,6 +44,7 @@ $note-form-margin-left: 72px; border: 1px solid $border-color; border-radius: $border-radius-default; margin: $gl-padding 0; + overflow: auto; &.system-note, &.note-form { diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 8e933b62dd9..2e81579d7b3 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -305,6 +305,7 @@ table.u2f-registrations { margin: 20px -5px 0; .bordered-box { + padding: 32px; border: 1px solid $blue-300; border-radius: $border-radius-default; background-color: $blue-50; @@ -461,3 +462,41 @@ table.u2f-registrations { .help-block { color: $gl-text-color-secondary; } + +.gitlab-slack-gif { + width: 100%; + max-width: $add-to-slack-gif-max-width; +} + +.gitlab-slack-well { + background-color: $white-light; + box-shadow: none; + max-width: $add-to-slack-well-max-width; +} + +.gitlab-slack-logo { + width: $add-to-slack-logo-size; + height: $add-to-slack-logo-size; +} + +.gitlab-slack-popup { + width: 100%; + max-width: $add-to-slack-popup-max-width; +} + +.gitlab-slack-right-arrow svg { + fill: $white-dark; + width: $right-arrow-size; + height: $right-arrow-size; + vertical-align: text-bottom; +} + +.gitlab-slack-double-headed-arrow { + vertical-align: text-top; + + svg { + fill: $gray-darker; + width: $double-headed-arrow-width; + height: $double-headed-arrow-height; + } +} diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 54126577f93..e4ed685bd1b 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -216,6 +216,31 @@ } } +.nested-settings { + padding-left: 20px; +} + +.input-btn-group { + display: flex; + + .input-large { + flex: 1; + } + + .btn { + margin-left: 10px; + } +} + +.settings-flex-row { + display: flex; + align-items: center; + + .float-right { + margin-left: auto; + } +} + .prometheus-metrics-monitoring { .card { .card-toggle { @@ -246,6 +271,27 @@ } } + .custom-monitored-metrics { + .card-title { + display: flex; + align-items: center; + + > .btn-success { + margin-left: auto; + } + } + + .custom-metric { + display: flex; + align-items: center; + } + + .custom-metric-link-bold { + font-weight: $gl-font-weight-bold; + text-decoration: none; + } + } + .loading-metrics, .empty-metrics { padding: 30px 10px; @@ -280,6 +326,12 @@ } } +.saml-settings.info-well { + .form-control[readonly] { + background: $white-light; + } +} + .modal-doorkeepr-auth { .modal-body { padding: $gl-padding; diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb new file mode 100644 index 00000000000..2987354b556 --- /dev/null +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true +module Types + module Ci + class DetailedStatusType < BaseObject + graphql_name 'DetailedStatus' + + field :group, GraphQL::STRING_TYPE, null: false + field :icon, GraphQL::STRING_TYPE, null: false + field :favicon, GraphQL::STRING_TYPE, null: false + field :details_path, GraphQL::STRING_TYPE, null: false + field :has_details, GraphQL::BOOLEAN_TYPE, null: false, method: :has_details? + field :label, GraphQL::STRING_TYPE, null: false + field :text, GraphQL::STRING_TYPE, null: false + field :tooltip, GraphQL::STRING_TYPE, null: false, method: :status_tooltip + end + end +end diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb index 2bbffad4563..18696293b97 100644 --- a/app/graphql/types/ci/pipeline_type.rb +++ b/app/graphql/types/ci/pipeline_type.rb @@ -13,6 +13,10 @@ module Types field :sha, GraphQL::STRING_TYPE, null: false field :before_sha, GraphQL::STRING_TYPE, null: true field :status, PipelineStatusEnum, null: false + field :detailed_status, + Types::Ci::DetailedStatusType, + null: false, + resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) } field :duration, GraphQL::INT_TYPE, null: true, diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index 916dcb1a308..769f75f57c4 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -14,4 +14,10 @@ module ClustersHelper render 'clusters/clusters/gcp_signup_offer_banner' end end + + def has_rbac_enabled?(cluster) + return cluster.platform_kubernetes_rbac? if cluster.platform_kubernetes + + !cluster.provider.legacy_abac? + end end diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index 941551dadaa..ec8f5cc40c0 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Runner < ActiveRecord::Base - VERSION = '0.2.0'.freeze + VERSION = '0.3.0'.freeze self.table_name = 'clusters_applications_runners' @@ -13,7 +13,7 @@ module Clusters include ::Clusters::Concerns::ApplicationData belongs_to :runner, class_name: 'Ci::Runner', foreign_key: :runner_id - delegate :project, to: :cluster + delegate :project, :group, to: :cluster default_value_for :version, VERSION @@ -55,12 +55,17 @@ module Clusters end def runner_create_params - { + attributes = { name: 'kubernetes-cluster', - runner_type: :project_type, - tag_list: %w(kubernetes cluster), - projects: [project] + runner_type: cluster.cluster_type, + tag_list: %w[kubernetes cluster] } + + if cluster.group_type? + attributes.merge(groups: [group]) + elsif cluster.project_type? + attributes.merge(projects: [project]) + end end def gitlab_url diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb index a9a2e9c81eb..52524456439 100644 --- a/app/models/commit_collection.rb +++ b/app/models/commit_collection.rb @@ -28,10 +28,43 @@ class CommitCollection def without_merge_commits strong_memoize(:without_merge_commits) do - commits.reject(&:merge_commit?) + # `#enrich!` the collection to ensure all commits contain + # the necessary parent data + enrich!.commits.reject(&:merge_commit?) end end + def unenriched + commits.reject(&:gitaly_commit?) + end + + def fully_enriched? + unenriched.empty? + end + + # Batch load any commits that are not backed by full gitaly data, and + # replace them in the collection. + def enrich! + # A project is needed in order to fetch data from gitaly. Projects + # can be absent from commits in certain rare situations (like when + # viewing a MR of a deleted fork). In these cases, assume that the + # enriched data is not needed. + return self if project.blank? || fully_enriched? + + # Batch load full Commits from the repository + # and map to a Hash of id => Commit + replacements = Hash[unenriched.map do |c| + [c.id, Commit.lazy(project, c.id)] + end.compact] + + # Replace the commits, keeping the same order + @commits = @commits.map do |c| + replacements.fetch(c.id, c) + end + + self + end + # Sets the pipeline status for every commit. # # Setting this status ahead of time removes the need for running a query for diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 15d8d58b9b5..28ea51d6769 100644 --- a/app/models/concerns/cache_markdown_field.rb +++ b/app/models/concerns/cache_markdown_field.rb @@ -15,7 +15,7 @@ module CacheMarkdownField # Increment this number every time the renderer changes its output CACHE_COMMONMARK_VERSION_START = 10 - CACHE_COMMONMARK_VERSION = 14 + CACHE_COMMONMARK_VERSION = 15 # changes to these attributes cause the cache to be invalidates INVALIDATED_BY = %w[author project].freeze diff --git a/app/services/after_branch_delete_service.rb b/app/services/after_branch_delete_service.rb index e7eb74d3e7d..ece9fbbef43 100644 --- a/app/services/after_branch_delete_service.rb +++ b/app/services/after_branch_delete_service.rb @@ -1,9 +1,6 @@ # frozen_string_literal: true -## -# Branch can be deleted either by DeleteBranchService -# or by GitPushService. -# +# Branch can be deleted either by DeleteBranchService or by Git::BranchPushService. class AfterBranchDeleteService < BaseService attr_reader :branch_name diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb index 5c4a34043c1..2292ec42b16 100644 --- a/app/services/ci/destroy_pipeline_service.rb +++ b/app/services/ci/destroy_pipeline_service.rb @@ -6,6 +6,8 @@ module Ci raise Gitlab::Access::AccessDeniedError unless can?(current_user, :destroy_pipeline, pipeline) pipeline.destroy! + + Gitlab::Cache::Ci::ProjectPipelineStatus.new(pipeline.project).delete_from_cache end end end diff --git a/app/services/clusters/applications/create_service.rb b/app/services/clusters/applications/create_service.rb index bd7c31bb981..c6f729aaa8a 100644 --- a/app/services/clusters/applications/create_service.rb +++ b/app/services/clusters/applications/create_service.rb @@ -13,7 +13,8 @@ module Clusters { "helm" => -> (cluster) { cluster.application_helm || cluster.build_application_helm }, "ingress" => -> (cluster) { cluster.application_ingress || cluster.build_application_ingress }, - "cert_manager" => -> (cluster) { cluster.application_cert_manager || cluster.build_application_cert_manager } + "cert_manager" => -> (cluster) { cluster.application_cert_manager || cluster.build_application_cert_manager }, + "runner" => -> (cluster) { cluster.application_runner || cluster.build_application_runner } }.tap do |hash| hash.merge!(project_builders) if cluster.project_type? end @@ -24,7 +25,6 @@ module Clusters def project_builders { "prometheus" => -> (cluster) { cluster.application_prometheus || cluster.build_application_prometheus }, - "runner" => -> (cluster) { cluster.application_runner || cluster.build_application_runner }, "jupyter" => -> (cluster) { cluster.application_jupyter || cluster.build_application_jupyter }, "knative" => -> (cluster) { cluster.application_knative || cluster.build_application_knative } } diff --git a/app/services/git/branch_push_service.rb b/app/services/git/branch_push_service.rb new file mode 100644 index 00000000000..b55aeb5f2b9 --- /dev/null +++ b/app/services/git/branch_push_service.rb @@ -0,0 +1,244 @@ +# frozen_string_literal: true + +module Git + class BranchPushService < BaseService + attr_accessor :push_data, :push_commits + include Gitlab::Access + include Gitlab::Utils::StrongMemoize + + # The N most recent commits to process in a single push payload. + PROCESS_COMMIT_LIMIT = 100 + + # This method will be called after each git update + # and only if the provided user and project are present in GitLab. + # + # All callbacks for post receive action should be placed here. + # + # Next, this method: + # 1. Creates the push event + # 2. Updates merge requests + # 3. Recognizes cross-references from commit messages + # 4. Executes the project's webhooks + # 5. Executes the project's services + # 6. Checks if the project's main language has changed + # + def execute + update_commits + execute_related_hooks + perform_housekeeping + + update_remote_mirrors + update_caches + + update_signatures + end + + def update_commits + project.repository.after_create if project.empty_repo? + project.repository.after_push_commit(branch_name) + + if push_remove_branch? + project.repository.after_remove_branch + @push_commits = [] + elsif push_to_new_branch? + project.repository.after_create_branch + + # Re-find the pushed commits. + if default_branch? + # Initial push to the default branch. Take the full history of that branch as "newly pushed". + process_default_branch + else + # Use the pushed commits that aren't reachable by the default branch + # as a heuristic. This may include more commits than are actually pushed, but + # that shouldn't matter because we check for existing cross-references later. + @push_commits = project.repository.commits_between(project.default_branch, params[:newrev]) + + # don't process commits for the initial push to the default branch + process_commit_messages + end + elsif push_to_existing_branch? + # Collect data for this git push + @push_commits = project.repository.commits_between(params[:oldrev], params[:newrev]) + + process_commit_messages + + # Update the bare repositories info/attributes file using the contents of the default branches + # .gitattributes file + update_gitattributes if default_branch? + end + end + + def update_gitattributes + project.repository.copy_gitattributes(params[:ref]) + end + + def update_caches + if default_branch? + if push_to_new_branch? + # If this is the initial push into the default branch, the file type caches + # will already be reset as a result of `Project#change_head`. + types = [] + else + paths = Set.new + + last_pushed_commits.each do |commit| + commit.raw_deltas.each do |diff| + paths << diff.new_path + end + end + + types = Gitlab::FileDetector.types_in_paths(paths.to_a) + end + + DetectRepositoryLanguagesWorker.perform_async(@project.id, current_user.id) + else + types = [] + end + + ProjectCacheWorker.perform_async(project.id, types, [:commit_count, :repository_size]) + end + + # rubocop: disable CodeReuse/ActiveRecord + def update_signatures + commit_shas = last_pushed_commits.map(&:sha) + + return if commit_shas.empty? + + shas_with_cached_signatures = GpgSignature.where(commit_sha: commit_shas).pluck(:commit_sha) + commit_shas -= shas_with_cached_signatures + + return if commit_shas.empty? + + commit_shas = Gitlab::Git::Commit.shas_with_signatures(project.repository, commit_shas) + + CreateGpgSignatureWorker.perform_async(commit_shas, project.id) + end + # rubocop: enable CodeReuse/ActiveRecord + + # Schedules processing of commit messages. + def process_commit_messages + default = default_branch? + + last_pushed_commits.each do |commit| + if commit.matches_cross_reference_regex? + ProcessCommitWorker + .perform_async(project.id, current_user.id, commit.to_hash, default) + end + end + end + + def update_remote_mirrors + return unless project.has_remote_mirror? + + project.mark_stuck_remote_mirrors_as_failed! + project.update_remote_mirrors + end + + def execute_related_hooks + # Update merge requests that may be affected by this push. A new branch + # could cause the last commit of a merge request to change. + # + UpdateMergeRequestsWorker + .perform_async(project.id, current_user.id, params[:oldrev], params[:newrev], params[:ref]) + + EventCreateService.new.push(project, current_user, build_push_data) + Ci::CreatePipelineService.new(project, current_user, build_push_data).execute(:push, pipeline_options) + + project.execute_hooks(build_push_data.dup, :push_hooks) + project.execute_services(build_push_data.dup, :push_hooks) + + if push_remove_branch? + AfterBranchDeleteService + .new(project, current_user) + .execute(branch_name) + end + end + + def perform_housekeeping + housekeeping = Projects::HousekeepingService.new(project) + housekeeping.increment! + housekeeping.execute if housekeeping.needed? + rescue Projects::HousekeepingService::LeaseTaken + end + + def process_default_branch + offset = [push_commits_count_for_ref - PROCESS_COMMIT_LIMIT, 0].max + @push_commits = project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT) + + project.after_create_default_branch + end + + def build_push_data + @push_data ||= Gitlab::DataBuilder::Push.build( + project, + current_user, + params[:oldrev], + params[:newrev], + params[:ref], + @push_commits, + commits_count: commits_count, + push_options: params[:push_options] || [] + ) + end + + def push_to_existing_branch? + # Return if this is not a push to a branch (e.g. new commits) + branch_ref? && !Gitlab::Git.blank_ref?(params[:oldrev]) + end + + def push_to_new_branch? + strong_memoize(:push_to_new_branch) do + branch_ref? && Gitlab::Git.blank_ref?(params[:oldrev]) + end + end + + def push_remove_branch? + strong_memoize(:push_remove_branch) do + branch_ref? && Gitlab::Git.blank_ref?(params[:newrev]) + end + end + + def default_branch? + branch_ref? && + (branch_name == project.default_branch || project.default_branch.nil?) + end + + def commit_user(commit) + commit.author || current_user + end + + def branch_name + strong_memoize(:branch_name) do + Gitlab::Git.ref_name(params[:ref]) + end + end + + def branch_ref? + strong_memoize(:branch_ref) do + Gitlab::Git.branch_ref?(params[:ref]) + end + end + + def commits_count + return push_commits_count_for_ref if default_branch? && push_to_new_branch? + + Array(@push_commits).size + end + + def push_commits_count_for_ref + strong_memoize(:push_commits_count_for_ref) do + project.repository.commit_count_for_ref(params[:ref]) + end + end + + def last_pushed_commits + @last_pushed_commits ||= @push_commits.last(PROCESS_COMMIT_LIMIT) + end + + private + + def pipeline_options + {} # to be overridden in EE + end + end +end diff --git a/app/services/git/tag_push_service.rb b/app/services/git/tag_push_service.rb new file mode 100644 index 00000000000..318dfd4f886 --- /dev/null +++ b/app/services/git/tag_push_service.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module Git + class TagPushService < BaseService + attr_accessor :push_data + + def execute + project.repository.after_create if project.empty_repo? + project.repository.before_push_tag + + @push_data = build_push_data + + EventCreateService.new.push(project, current_user, push_data) + Ci::CreatePipelineService.new(project, current_user, push_data).execute(:push, pipeline_options) + + SystemHooksService.new.execute_hooks(build_system_push_data, :tag_push_hooks) + project.execute_hooks(push_data.dup, :tag_push_hooks) + project.execute_services(push_data.dup, :tag_push_hooks) + + ProjectCacheWorker.perform_async(project.id, [], [:commit_count, :repository_size]) + + true + end + + private + + def build_push_data + commits = [] + message = nil + + unless Gitlab::Git.blank_ref?(params[:newrev]) + tag_name = Gitlab::Git.ref_name(params[:ref]) + tag = project.repository.find_tag(tag_name) + + if tag && tag.target == params[:newrev] + commit = project.commit(tag.dereferenced_target) + commits = [commit].compact + message = tag.message + end + end + + Gitlab::DataBuilder::Push.build( + project, + current_user, + params[:oldrev], + params[:newrev], + params[:ref], + commits, + message, + push_options: params[:push_options] || []) + end + + def build_system_push_data + Gitlab::DataBuilder::Push.build( + project, + current_user, + params[:oldrev], + params[:newrev], + params[:ref], + [], + '') + end + + def pipeline_options + {} # to be overridden in EE + end + end +end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb deleted file mode 100644 index f387c749a21..00000000000 --- a/app/services/git_push_service.rb +++ /dev/null @@ -1,240 +0,0 @@ -# frozen_string_literal: true - -class GitPushService < BaseService - attr_accessor :push_data, :push_commits - include Gitlab::Access - include Gitlab::Utils::StrongMemoize - - # The N most recent commits to process in a single push payload. - PROCESS_COMMIT_LIMIT = 100 - - # This method will be called after each git update - # and only if the provided user and project are present in GitLab. - # - # All callbacks for post receive action should be placed here. - # - # Next, this method: - # 1. Creates the push event - # 2. Updates merge requests - # 3. Recognizes cross-references from commit messages - # 4. Executes the project's webhooks - # 5. Executes the project's services - # 6. Checks if the project's main language has changed - # - def execute - project.repository.after_create if project.empty_repo? - project.repository.after_push_commit(branch_name) - - if push_remove_branch? - project.repository.after_remove_branch - @push_commits = [] - elsif push_to_new_branch? - project.repository.after_create_branch - - # Re-find the pushed commits. - if default_branch? - # Initial push to the default branch. Take the full history of that branch as "newly pushed". - process_default_branch - else - # Use the pushed commits that aren't reachable by the default branch - # as a heuristic. This may include more commits than are actually pushed, but - # that shouldn't matter because we check for existing cross-references later. - @push_commits = project.repository.commits_between(project.default_branch, params[:newrev]) - - # don't process commits for the initial push to the default branch - process_commit_messages - end - elsif push_to_existing_branch? - # Collect data for this git push - @push_commits = project.repository.commits_between(params[:oldrev], params[:newrev]) - - process_commit_messages - - # Update the bare repositories info/attributes file using the contents of the default branches - # .gitattributes file - update_gitattributes if default_branch? - end - - execute_related_hooks - perform_housekeeping - - update_remote_mirrors - update_caches - - update_signatures - end - - def update_gitattributes - project.repository.copy_gitattributes(params[:ref]) - end - - def update_caches - if default_branch? - if push_to_new_branch? - # If this is the initial push into the default branch, the file type caches - # will already be reset as a result of `Project#change_head`. - types = [] - else - paths = Set.new - - last_pushed_commits.each do |commit| - commit.raw_deltas.each do |diff| - paths << diff.new_path - end - end - - types = Gitlab::FileDetector.types_in_paths(paths.to_a) - end - - DetectRepositoryLanguagesWorker.perform_async(@project.id, current_user.id) - else - types = [] - end - - ProjectCacheWorker.perform_async(project.id, types, [:commit_count, :repository_size]) - end - - # rubocop: disable CodeReuse/ActiveRecord - def update_signatures - commit_shas = last_pushed_commits.map(&:sha) - - return if commit_shas.empty? - - shas_with_cached_signatures = GpgSignature.where(commit_sha: commit_shas).pluck(:commit_sha) - commit_shas -= shas_with_cached_signatures - - return if commit_shas.empty? - - commit_shas = Gitlab::Git::Commit.shas_with_signatures(project.repository, commit_shas) - - CreateGpgSignatureWorker.perform_async(commit_shas, project.id) - end - # rubocop: enable CodeReuse/ActiveRecord - - # Schedules processing of commit messages. - def process_commit_messages - default = default_branch? - - last_pushed_commits.each do |commit| - if commit.matches_cross_reference_regex? - ProcessCommitWorker - .perform_async(project.id, current_user.id, commit.to_hash, default) - end - end - end - - protected - - def update_remote_mirrors - return unless project.has_remote_mirror? - - project.mark_stuck_remote_mirrors_as_failed! - project.update_remote_mirrors - end - - def execute_related_hooks - # Update merge requests that may be affected by this push. A new branch - # could cause the last commit of a merge request to change. - # - UpdateMergeRequestsWorker - .perform_async(project.id, current_user.id, params[:oldrev], params[:newrev], params[:ref]) - - EventCreateService.new.push(project, current_user, build_push_data) - Ci::CreatePipelineService.new(project, current_user, build_push_data).execute(:push, pipeline_options) - - project.execute_hooks(build_push_data.dup, :push_hooks) - project.execute_services(build_push_data.dup, :push_hooks) - - if push_remove_branch? - AfterBranchDeleteService - .new(project, current_user) - .execute(branch_name) - end - end - - def perform_housekeeping - housekeeping = Projects::HousekeepingService.new(project) - housekeeping.increment! - housekeeping.execute if housekeeping.needed? - rescue Projects::HousekeepingService::LeaseTaken - end - - def process_default_branch - offset = [push_commits_count_for_ref - PROCESS_COMMIT_LIMIT, 0].max - @push_commits = project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT) - - project.after_create_default_branch - end - - def build_push_data - @push_data ||= Gitlab::DataBuilder::Push.build( - project, - current_user, - params[:oldrev], - params[:newrev], - params[:ref], - @push_commits, - commits_count: commits_count, - push_options: params[:push_options] || []) - end - - def push_to_existing_branch? - # Return if this is not a push to a branch (e.g. new commits) - branch_ref? && !Gitlab::Git.blank_ref?(params[:oldrev]) - end - - def push_to_new_branch? - strong_memoize(:push_to_new_branch) do - branch_ref? && Gitlab::Git.blank_ref?(params[:oldrev]) - end - end - - def push_remove_branch? - strong_memoize(:push_remove_branch) do - branch_ref? && Gitlab::Git.blank_ref?(params[:newrev]) - end - end - - def default_branch? - branch_ref? && - (branch_name == project.default_branch || project.default_branch.nil?) - end - - def commit_user(commit) - commit.author || current_user - end - - def branch_name - strong_memoize(:branch_name) do - Gitlab::Git.ref_name(params[:ref]) - end - end - - def branch_ref? - strong_memoize(:branch_ref) do - Gitlab::Git.branch_ref?(params[:ref]) - end - end - - def commits_count - return push_commits_count_for_ref if default_branch? && push_to_new_branch? - - Array(@push_commits).size - end - - def push_commits_count_for_ref - strong_memoize(:push_commits_count_for_ref) do - project.repository.commit_count_for_ref(params[:ref]) - end - end - - def last_pushed_commits - @last_pushed_commits ||= @push_commits.last(PROCESS_COMMIT_LIMIT) - end - - private - - def pipeline_options - {} # to be overridden in EE - end -end diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb deleted file mode 100644 index e39b3603c6c..00000000000 --- a/app/services/git_tag_push_service.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -class GitTagPushService < BaseService - attr_accessor :push_data - - def execute - project.repository.after_create if project.empty_repo? - project.repository.before_push_tag - - @push_data = build_push_data - - EventCreateService.new.push(project, current_user, push_data) - Ci::CreatePipelineService.new(project, current_user, push_data).execute(:push, pipeline_options) - - SystemHooksService.new.execute_hooks(build_system_push_data, :tag_push_hooks) - project.execute_hooks(push_data.dup, :tag_push_hooks) - project.execute_services(push_data.dup, :tag_push_hooks) - - ProjectCacheWorker.perform_async(project.id, [], [:commit_count, :repository_size]) - - true - end - - private - - def build_push_data - commits = [] - message = nil - - unless Gitlab::Git.blank_ref?(params[:newrev]) - tag_name = Gitlab::Git.ref_name(params[:ref]) - tag = project.repository.find_tag(tag_name) - - if tag && tag.target == params[:newrev] - commit = project.commit(tag.dereferenced_target) - commits = [commit].compact - message = tag.message - end - end - - Gitlab::DataBuilder::Push.build( - project, - current_user, - params[:oldrev], - params[:newrev], - params[:ref], - commits, - message, - push_options: params[:push_options] || []) - end - - def build_system_push_data - Gitlab::DataBuilder::Push.build( - project, - current_user, - params[:oldrev], - params[:newrev], - params[:ref], - [], - '') - end - - def pipeline_options - {} # to be overridden in EE - end -end diff --git a/app/services/releases/destroy_service.rb b/app/services/releases/destroy_service.rb index 8c2bc3b4e6e..f9f6101abdd 100644 --- a/app/services/releases/destroy_service.rb +++ b/app/services/releases/destroy_service.rb @@ -5,7 +5,6 @@ module Releases include Releases::Concerns def execute - return error('Tag does not exist', 404) unless existing_tag return error('Release does not exist', 404) unless release return error('Access Denied', 403) unless allowed? diff --git a/app/views/clusters/clusters/show.html.haml b/app/views/clusters/clusters/show.html.haml index 68d9510e1bf..61188c6fa0b 100644 --- a/app/views/clusters/clusters/show.html.haml +++ b/app/views/clusters/clusters/show.html.haml @@ -17,7 +17,7 @@ install_knative_path: clusterable.install_applications_cluster_path(@cluster, :knative), update_knative_path: clusterable.update_applications_cluster_path(@cluster, :knative), toggle_status: @cluster.enabled? ? 'true': 'false', - has_rbac: @cluster.platform_kubernetes_rbac? ? 'true': 'false', + has_rbac: has_rbac_enabled?(@cluster) ? 'true': 'false', cluster_type: @cluster.cluster_type, cluster_status: @cluster.status_name, cluster_status_reason: @cluster.status_reason, diff --git a/app/views/dashboard/groups/_groups.html.haml b/app/views/dashboard/groups/_groups.html.haml index db856ef7d7b..2f9dbf87d95 100644 --- a/app/views/dashboard/groups/_groups.html.haml +++ b/app/views/dashboard/groups/_groups.html.haml @@ -1,4 +1,4 @@ .js-groups-list-holder #js-groups-tree{ data: { hide_projects: 'true', endpoint: dashboard_groups_path(format: :json), path: dashboard_groups_path, form_sel: 'form#group-filter-form', filter_sel: '.js-groups-list-filter', holder_sel: '.js-groups-list-holder', dropdown_sel: '.js-group-filter-dropdown-wrap' } } - .loading-container.text-center - = icon('spinner spin 2x', class: 'loading-animation prepend-top-20') + .loading-container.text-center.prepend-top-20 + .spinner.spinner-md diff --git a/app/views/explore/groups/_groups.html.haml b/app/views/explore/groups/_groups.html.haml index ff57b39e947..a3249275d5e 100644 --- a/app/views/explore/groups/_groups.html.haml +++ b/app/views/explore/groups/_groups.html.haml @@ -1,4 +1,4 @@ .js-groups-list-holder #js-groups-tree{ data: { hide_projects: 'true', endpoint: explore_groups_path(format: :json), path: explore_groups_path, form_sel: 'form#group-filter-form', filter_sel: '.js-groups-list-filter', holder_sel: '.js-groups-list-holder', dropdown_sel: '.js-group-filter-dropdown-wrap' } } - .loading-container.text-center - = icon('spinner spin 2x', class: 'loading-animation prepend-top-20') + .loading-container.text-center.prepend-top-20 + .spinner.spinner-md diff --git a/app/views/groups/_archived_projects.html.haml b/app/views/groups/_archived_projects.html.haml index ed79f5790f0..48e9f630050 100644 --- a/app/views/groups/_archived_projects.html.haml +++ b/app/views/groups/_archived_projects.html.haml @@ -4,5 +4,5 @@ %ul.content-list{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } } .js-groups-list-holder - .loading-container.text-center - = icon('spinner spin 2x', class: 'loading-animation prepend-top-20') + .loading-container.text-center.prepend-top-20 + .spinner.spinner-md diff --git a/app/views/groups/_shared_projects.html.haml b/app/views/groups/_shared_projects.html.haml index 4eb8367f633..2769b69add3 100644 --- a/app/views/groups/_shared_projects.html.haml +++ b/app/views/groups/_shared_projects.html.haml @@ -4,5 +4,5 @@ %ul.content-list{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } } .js-groups-list-holder - .loading-container.text-center - = icon('spinner spin 2x', class: 'loading-animation prepend-top-20') + .loading-container.text-center.prepend-top-20 + .spinner.spinner-md diff --git a/app/views/groups/_subgroups_and_projects.html.haml b/app/views/groups/_subgroups_and_projects.html.haml index d53c8026df8..784f5ac233e 100644 --- a/app/views/groups/_subgroups_and_projects.html.haml +++ b/app/views/groups/_subgroups_and_projects.html.haml @@ -4,5 +4,5 @@ %ul.content-list{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } } .js-groups-list-holder - .loading-container.text-center - = icon('spinner spin 2x', class: 'loading-animation prepend-top-20') + .loading-container.text-center.prepend-top-20 + .spinner.spinner-md diff --git a/app/workers/create_gpg_signature_worker.rb b/app/workers/create_gpg_signature_worker.rb index 2827529cc1c..7fac7822cf7 100644 --- a/app/workers/create_gpg_signature_worker.rb +++ b/app/workers/create_gpg_signature_worker.rb @@ -5,8 +5,8 @@ class CreateGpgSignatureWorker # rubocop: disable CodeReuse/ActiveRecord def perform(commit_shas, project_id) - # Older versions of GitPushService may push a single commit ID on the stack. - # We need this to be backwards compatible. + # Older versions of Git::BranchPushService may push a single commit ID on + # the stack. We need this to be backwards compatible. commit_shas = Array(commit_shas) return if commit_shas.empty? diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index bbd4ab159e4..a40c865a5e5 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -38,7 +38,7 @@ class PostReceive post_received.changes_refs do |oldrev, newrev, ref| if Gitlab::Git.tag_ref?(ref) - GitTagPushService.new( + Git::TagPushService.new( post_received.project, @user, oldrev: oldrev, @@ -46,7 +46,7 @@ class PostReceive ref: ref, push_options: post_received.push_options).execute elsif Gitlab::Git.branch_ref?(ref) - GitPushService.new( + Git::BranchPushService.new( post_received.project, @user, oldrev: oldrev, diff --git a/changelogs/unreleased/48297-fix-code-selection.yml b/changelogs/unreleased/48297-fix-code-selection.yml new file mode 100644 index 00000000000..14841b00969 --- /dev/null +++ b/changelogs/unreleased/48297-fix-code-selection.yml @@ -0,0 +1,6 @@ +--- +title: Resolve Code in other column of side-by-side diff is highlighted when selecting + code on one side +merge_request: 26423 +author: +type: fixed diff --git a/changelogs/unreleased/51988-install-group-runner-on-group-cluster.yml b/changelogs/unreleased/51988-install-group-runner-on-group-cluster.yml new file mode 100644 index 00000000000..86f08dd1798 --- /dev/null +++ b/changelogs/unreleased/51988-install-group-runner-on-group-cluster.yml @@ -0,0 +1,5 @@ +--- +title: Support installing Group runner on group-level cluster +merge_request: 26260 +author: +type: added diff --git a/changelogs/unreleased/52366-improved-group-lists-ui-spinners.yml b/changelogs/unreleased/52366-improved-group-lists-ui-spinners.yml new file mode 100644 index 00000000000..ab09272eaf4 --- /dev/null +++ b/changelogs/unreleased/52366-improved-group-lists-ui-spinners.yml @@ -0,0 +1,5 @@ +--- +title: Update spinners in group list component +merge_request: 26572 +author: +type: changed diff --git a/changelogs/unreleased/54916-extended-tooltip-for-merge-request-links.yml b/changelogs/unreleased/54916-extended-tooltip-for-merge-request-links.yml new file mode 100644 index 00000000000..7fd0bcd1c00 --- /dev/null +++ b/changelogs/unreleased/54916-extended-tooltip-for-merge-request-links.yml @@ -0,0 +1,5 @@ +--- +title: Add extended merge request tooltip +merge_request: !25221 +author: +type: added diff --git a/changelogs/unreleased/56954-improve-knative-after-installing-tiller.yml b/changelogs/unreleased/56954-improve-knative-after-installing-tiller.yml new file mode 100644 index 00000000000..b9fb27c3218 --- /dev/null +++ b/changelogs/unreleased/56954-improve-knative-after-installing-tiller.yml @@ -0,0 +1,5 @@ +--- +title: Improve the Knative installation on Clusters +merge_request: 26339 +author: +type: added diff --git a/changelogs/unreleased/57409-loading-button-transition.yml b/changelogs/unreleased/57409-loading-button-transition.yml new file mode 100644 index 00000000000..3cf169d79de --- /dev/null +++ b/changelogs/unreleased/57409-loading-button-transition.yml @@ -0,0 +1,5 @@ +--- +title: Prevent fade out transition on loading-button component. +merge_request: 26428 +author: +type: fixed diff --git a/changelogs/unreleased/57648-make-emoji-picker-full-width-on-mobile.yml b/changelogs/unreleased/57648-make-emoji-picker-full-width-on-mobile.yml new file mode 100644 index 00000000000..d92fd2a762e --- /dev/null +++ b/changelogs/unreleased/57648-make-emoji-picker-full-width-on-mobile.yml @@ -0,0 +1,5 @@ +--- +title: Makes emoji picker full width on mobile. +merge_request: 25883 +author: Jacopo Beschi @jacopo-beschi +type: fixed diff --git a/changelogs/unreleased/57984-store-branch-name.yml b/changelogs/unreleased/57984-store-branch-name.yml new file mode 100644 index 00000000000..26dfdb7a5d6 --- /dev/null +++ b/changelogs/unreleased/57984-store-branch-name.yml @@ -0,0 +1,5 @@ +--- +title: Resolves Branch name is lost if I change commit mode in Web IDE +merge_request: 26180 +author: +type: fixed diff --git a/changelogs/unreleased/58805-allow-incomplete-commit-data-to-be-fetched-from-collection.yml b/changelogs/unreleased/58805-allow-incomplete-commit-data-to-be-fetched-from-collection.yml new file mode 100644 index 00000000000..4377ebfdbdf --- /dev/null +++ b/changelogs/unreleased/58805-allow-incomplete-commit-data-to-be-fetched-from-collection.yml @@ -0,0 +1,5 @@ +--- +title: Fix merge commits being used as default squash commit messages +merge_request: 26445 +author: +type: fixed diff --git a/changelogs/unreleased/58999-z-index-issue-on-pipeline-dropdown.yml b/changelogs/unreleased/58999-z-index-issue-on-pipeline-dropdown.yml deleted file mode 100644 index 9a7a0e5af37..00000000000 --- a/changelogs/unreleased/58999-z-index-issue-on-pipeline-dropdown.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix issue that caused the "Show all activity" button to appear on top of the - mini pipeline status dropdown on the merge request page -merge_request: 26274 -author: -type: fixed diff --git a/changelogs/unreleased/59147-duplicate-match-line.yml b/changelogs/unreleased/59147-duplicate-match-line.yml deleted file mode 100644 index 378d2a40386..00000000000 --- a/changelogs/unreleased/59147-duplicate-match-line.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix duplicated bottom match line on merge request parallel diff view -merge_request: 26402 -author: -type: fixed diff --git a/changelogs/unreleased/59289-fix-push-to-create-protected-branches.yml b/changelogs/unreleased/59289-fix-push-to-create-protected-branches.yml deleted file mode 100644 index 76dd63fef7a..00000000000 --- a/changelogs/unreleased/59289-fix-push-to-create-protected-branches.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Allow users who can push to protected branches to create protected branches - via CLI -merge_request: 26413 -author: -type: fixed diff --git a/changelogs/unreleased/59293-android-template-is-missing-gitlab-ci-yml.yml b/changelogs/unreleased/59293-android-template-is-missing-gitlab-ci-yml.yml deleted file mode 100644 index ea559e74a2d..00000000000 --- a/changelogs/unreleased/59293-android-template-is-missing-gitlab-ci-yml.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add missing .gitlab-ci.yml to Android template -merge_request: 26415 -author: -type: fixed diff --git a/changelogs/unreleased/59352-fix-mr-discussion-expansion.yml b/changelogs/unreleased/59352-fix-mr-discussion-expansion.yml new file mode 100644 index 00000000000..ab9ad53835c --- /dev/null +++ b/changelogs/unreleased/59352-fix-mr-discussion-expansion.yml @@ -0,0 +1,5 @@ +--- +title: Expand resolved discussion when linking to a comment in the discussion +merge_request: 26483 +author: +type: fixed diff --git a/changelogs/unreleased/MaxWinterstein-master-patch-23232.yml b/changelogs/unreleased/MaxWinterstein-master-patch-23232.yml new file mode 100644 index 00000000000..8fb9f1057fe --- /dev/null +++ b/changelogs/unreleased/MaxWinterstein-master-patch-23232.yml @@ -0,0 +1,5 @@ +--- +title: Unify behaviour of 'Copy commit SHA to clipboard' to use full commit SHA. +merge_request: 25829 +author: Max Winterstein +type: changed diff --git a/changelogs/unreleased/ce-56153-error-tracking-counts.yml b/changelogs/unreleased/ce-56153-error-tracking-counts.yml new file mode 100644 index 00000000000..fc3d8c01d7f --- /dev/null +++ b/changelogs/unreleased/ce-56153-error-tracking-counts.yml @@ -0,0 +1,5 @@ +--- +title: Add usage counts for error tracking feature +merge_request: 25472 +author: +type: added diff --git a/changelogs/unreleased/delete-release-when-delete-tag.yml b/changelogs/unreleased/delete-release-when-delete-tag.yml new file mode 100644 index 00000000000..58acd449bf1 --- /dev/null +++ b/changelogs/unreleased/delete-release-when-delete-tag.yml @@ -0,0 +1,5 @@ +--- +title: Releases will now be automatically deleted when deleting corresponding tag +merge_request: 26530 +author: +type: fixed diff --git a/changelogs/unreleased/fix-missing-border.yml b/changelogs/unreleased/fix-missing-border.yml new file mode 100644 index 00000000000..21728223cb8 --- /dev/null +++ b/changelogs/unreleased/fix-missing-border.yml @@ -0,0 +1,5 @@ +--- +title: Fixes missing border color in discussion card component +merge_request: 26242 +author: Farhad Yasir +type: fixed diff --git a/changelogs/unreleased/recreate-all-diffs-on-import.yml b/changelogs/unreleased/recreate-all-diffs-on-import.yml new file mode 100644 index 00000000000..fd9124372f3 --- /dev/null +++ b/changelogs/unreleased/recreate-all-diffs-on-import.yml @@ -0,0 +1,5 @@ +--- +title: Force to recreate all MR diffs on import +merge_request: 26480 +author: +type: fixed diff --git a/changelogs/unreleased/refresh-commit-count-after-head-change.yml b/changelogs/unreleased/refresh-commit-count-after-head-change.yml deleted file mode 100644 index 27e278958b8..00000000000 --- a/changelogs/unreleased/refresh-commit-count-after-head-change.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Refresh commit count after repository head changes -merge_request: 26473 -author: -type: fixed diff --git a/changelogs/unreleased/retain-default-branch-on-import.yml b/changelogs/unreleased/retain-default-branch-on-import.yml deleted file mode 100644 index c83ccf39a27..00000000000 --- a/changelogs/unreleased/retain-default-branch-on-import.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Set proper default-branch for repository on GitHub Import -merge_request: 26476 -author: -type: fixed diff --git a/changelogs/unreleased/sh-clear-pipeline-status-cache-upon-destroy.yml b/changelogs/unreleased/sh-clear-pipeline-status-cache-upon-destroy.yml new file mode 100644 index 00000000000..55779f0f9d3 --- /dev/null +++ b/changelogs/unreleased/sh-clear-pipeline-status-cache-upon-destroy.yml @@ -0,0 +1,5 @@ +--- +title: Clear pipeline status cache after destruction of pipeline +merge_request: 26575 +author: +type: fixed diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-3-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-3-0.yml new file mode 100644 index 00000000000..2e1adb1e1e9 --- /dev/null +++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-3-0.yml @@ -0,0 +1,5 @@ +--- +title: Update GitLab Runner Helm Chart to 0.3.0/11.9.0 +merge_request: 26467 +author: +type: other diff --git a/config/karma.config.js b/config/karma.config.js index c30c58edc6f..7e1e89f3c10 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -110,7 +110,7 @@ module.exports = function(config) { frameworks: ['jasmine'], files: [ { pattern: 'spec/javascripts/test_bundle.js', watched: false }, - { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw|.png)', included: false }, + { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.png)', included: false }, ], preprocessors: { 'spec/javascripts/**/*.js': ['webpack', 'sourcemap'], diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md index 2d4b5c65c46..02a352b1f3f 100644 --- a/doc/administration/gitaly/index.md +++ b/doc/administration/gitaly/index.md @@ -241,12 +241,24 @@ repository from your GitLab server over HTTP. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22602) in GitLab 11.8. -Gitaly supports TLS credentials for GRPC authentication. To be able to communicate +Gitaly supports TLS encryption. To be able to communicate with a Gitaly instance that listens for secure connections you will need to use `tls://` url scheme in the `gitaly_address` of the corresponding storage entry in the gitlab configuration. The admin needs to bring their own certificate as we do not provide that automatically. -The certificate to be used needs to be installed on all Gitaly nodes and on all client nodes that communicate with it following procedures described in [GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates) +The certificate to be used needs to be installed on all Gitaly nodes and on all client nodes that communicate with it following procedures described in [GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates). + +Note that it is possible to configure Gitaly servers with both an +unencrypted listening address `listen_addr` and an encrypted listening +address `tls_listen_addr` at the same time. This allows you to do a +gradual transition from unencrypted to encrypted traffic, if necessary. + +To observe what type of connections are actually being used in a +production environment you can use the following Prometheus query: + +``` +sum(rate(gitaly_connections_total[5m])) by (type) +``` ### Example TLS configuration diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md index 7f25423171f..1689b0a57d6 100644 --- a/doc/administration/repository_storage_paths.md +++ b/doc/administration/repository_storage_paths.md @@ -62,6 +62,8 @@ files and add the full paths of the alternative repository storage paths. In the example below, we add two more mountpoints that are named `nfs` and `cephfs` respectively. +NOTE: **Note:** This example uses NFS and CephFS. We do not recommend using EFS for storage as it may impact GitLab's performance. See the [relevant documentation](./high_availability/nfs.md#avoid-using-awss-elastic-file-system-efs) for more details. + **For installations from source** 1. Edit `gitlab.yml` and add the storage paths: diff --git a/doc/api/commits.md b/doc/api/commits.md index 442178aedff..09546fcac3f 100644 --- a/doc/api/commits.md +++ b/doc/api/commits.md @@ -475,7 +475,7 @@ GET /projects/:id/repository/commits/:sha/statuses | `sha` | string | yes | The commit SHA | `ref` | string | no | The name of a repository branch or tag or, if not given, the default branch | `stage` | string | no | Filter by [build stage](../ci/yaml/README.md#stages), e.g., `test` -| `name` | string | no | Filter by [job name](../ci/yaml/README.md#jobs), e.g., `bundler:audit` +| `name` | string | no | Filter by [job name](../ci/yaml/README.md#introduction), e.g., `bundler:audit` | `all` | boolean | no | Return all statuses, not only the latest ones ```bash diff --git a/doc/api/releases/links.md b/doc/api/releases/links.md index fd7b9d6e6e2..9c91264ed65 100644 --- a/doc/api/releases/links.md +++ b/doc/api/releases/links.md @@ -15,7 +15,7 @@ GET /projects/:id/releases/:tag_name/assets/links | Attribute | Type | Required | Description | | ------------- | -------------- | -------- | --------------------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). | | `tag_name` | string | yes | The tag associated with the Release. | Example request: @@ -53,7 +53,7 @@ GET /projects/:id/releases/:tag_name/assets/links/:link_id | Attribute | Type | Required | Description | | ------------- | -------------- | -------- | --------------------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). | | `tag_name` | string | yes | The tag associated with the Release. | | `link_id` | integer | yes | The id of the link. | @@ -84,7 +84,7 @@ POST /projects/:id/releases/:tag_name/assets/links | Attribute | Type | Required | Description | | ------------- | -------------- | -------- | --------------------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). | | `tag_name` | string | yes | The tag associated with the Release. | | `name` | string | yes | The name of the link. | | `url` | string | yes | The URL of the link. | @@ -120,7 +120,7 @@ PUT /projects/:id/releases/:tag_name/assets/links/:link_id | Attribute | Type | Required | Description | | ------------- | -------------- | -------- | --------------------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). | | `tag_name` | string | yes | The tag associated with the Release. | | `link_id` | integer | yes | The id of the link. | | `name` | string | no | The name of the link. | @@ -156,7 +156,7 @@ DELETE /projects/:id/releases/:tag_name/assets/links/:link_id | Attribute | Type | Required | Description | | ------------- | -------------- | -------- | --------------------------------------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). | | `tag_name` | string | yes | The tag associated with the Release. | | `link_id` | integer | yes | The id of the link. | diff --git a/doc/articles/artifactory_and_gitlab/index.md b/doc/articles/artifactory_and_gitlab/index.md index 6a590b53727..ed9fd135e7c 100644 --- a/doc/articles/artifactory_and_gitlab/index.md +++ b/doc/articles/artifactory_and_gitlab/index.md @@ -1 +1,5 @@ +--- +redirect_to: '../../ci/examples/artifactory_and_gitlab/index.md' +--- + This document was moved to [another location](../../ci/examples/artifactory_and_gitlab/index.md) diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md index a8320c12e6b..8e2e54711e7 100644 --- a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md +++ b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md @@ -1 +1,5 @@ +--- +redirect_to: '../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md' +--- + This document was moved to [another location](../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md). diff --git a/doc/articles/how_to_install_git/index.md b/doc/articles/how_to_install_git/index.md index 3e6003a33b7..62598101895 100644 --- a/doc/articles/how_to_install_git/index.md +++ b/doc/articles/how_to_install_git/index.md @@ -1 +1,5 @@ +--- +redirect_to: '../../topics/git/how_to_install_git/index.md' +--- + This document was moved to [another location](../../topics/git/how_to_install_git/index.md). diff --git a/doc/articles/laravel_with_gitlab_and_envoy/index.md b/doc/articles/laravel_with_gitlab_and_envoy/index.md index b092cdb0f7a..fa4f6243410 100644 --- a/doc/articles/laravel_with_gitlab_and_envoy/index.md +++ b/doc/articles/laravel_with_gitlab_and_envoy/index.md @@ -1 +1,5 @@ +--- +redirect_to: '../../ci/examples/laravel_with_gitlab_and_envoy/index.md' +--- + This document was moved to [another location](../../ci/examples/laravel_with_gitlab_and_envoy/index.md). diff --git a/doc/articles/numerous_undo_possibilities_in_git/index.md b/doc/articles/numerous_undo_possibilities_in_git/index.md index 3f46ee9a5e6..83aac82db4e 100644 --- a/doc/articles/numerous_undo_possibilities_in_git/index.md +++ b/doc/articles/numerous_undo_possibilities_in_git/index.md @@ -1 +1,5 @@ +--- +redirect_to: '../../topics/git/numerous_undo_possibilities_in_git/index.md' +--- + This document was moved to [another location](../../topics/git/numerous_undo_possibilities_in_git/index.md). diff --git a/doc/articles/runner_autoscale_aws/index.md b/doc/articles/runner_autoscale_aws/index.md index e2667aebc5f..fb769731256 100644 --- a/doc/articles/runner_autoscale_aws/index.md +++ b/doc/articles/runner_autoscale_aws/index.md @@ -1 +1,5 @@ +--- +redirect_to: 'https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/index.html' +--- + This document was moved to [another location](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/index.html). diff --git a/doc/ci/environments.md b/doc/ci/environments.md index fe66f7e3c28..05d392d54cb 100644 --- a/doc/ci/environments.md +++ b/doc/ci/environments.md @@ -21,7 +21,7 @@ all within GitLab. All you need to do is define them in your project's history of your deployments per every environment. Environments are like tags for your CI jobs, describing where code gets deployed. -Deployments are created when [jobs] deploy versions of code to environments, +Deployments are created when [jobs](yaml/README.md#introduction) deploy versions of code to environments, so every environment can have one or more deployments. GitLab keeps track of your deployments, so you always know what is currently being deployed on your servers. If you have a deployment service such as [Kubernetes][kube] @@ -103,7 +103,7 @@ the Git SHA and environment name. To sum up, with the above `.gitlab-ci.yml` we have achieved that: - All branches will run the `test` and `build` jobs. -- The `deploy_staging` job will run [only](yaml/README.md#only-and-except-simplified) on the `master` +- The `deploy_staging` job will run [only](yaml/README.md#onlyexcept-basic) on the `master` branch which means all merge requests that are created from branches don't get to deploy to the staging server - When a merge request is merged, all jobs will run and the `deploy_staging` @@ -298,8 +298,8 @@ here because it is guaranteed to be unique, but if you're using a workflow like environment names to be more closely based on the branch name - the example above would give you an URL like `https://100-do-the-thing.example.com` -Last but not least, we tell the job to run [`only`][only] on branches -[`except`][only] master. +Last but not least, we tell the job to run [`only`](yaml/README.md#onlyexcept-basic) on branches +[`except`](yaml/README.md#onlyexcept-basic) master. >**Note:** You are not bound to use the same prefix or only slashes in the dynamic @@ -613,14 +613,12 @@ Below are some links you may find interesting: - [Review Apps - Use dynamic environments to deploy your code for every branch](review_apps/index.md) [Pipelines]: pipelines.md -[jobs]: yaml/README.md#jobs [yaml]: yaml/README.md [environments]: #environments [deployments]: #deployments [permissions]: ../user/permissions.md [variables]: variables/README.md [env-name]: yaml/README.md#environmentname -[only]: yaml/README.md#only-and-except-simplified [onstop]: yaml/README.md#environmenton_stop [ce-7015]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7015 [gitlab-flow]: ../workflow/gitlab_flow.md diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index a1c997d1de6..7f686781e3c 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -50,6 +50,10 @@ language users and GitLab by sending a merge request with a guide for that langu You may want to apply for the [GitLab Community Writers Program](https://about.gitlab.com/community-writers/) to get paid for writing complete articles for GitLab. +### Adding templates to your GitLab installation **[PREMIUM ONLY]** + +If you want to have customized examples and templates for your own self-managed GitLab instance available to your team, your GitLab administrator can [designate an instance template repository](https://docs.gitlab.com/ee/user/admin_area/settings/instance_template_repository.html) that contains examples and templates specific to your enterprise. + ## Other resources This section provides further resources to help you get familiar with different aspects of GitLab CI/CD. diff --git a/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md b/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md index d9152c45595..cf281605f5e 100644 --- a/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md +++ b/doc/ci/examples/deploy_spring_boot_to_cloud_foundry/index.md @@ -99,7 +99,7 @@ We've used the `java:8` [docker image](../../docker/using_docker_images.md) to build our application as it provides the up-to-date Java 8 JDK on [Docker Hub](https://hub.docker.com/). We've also added the [`only` -clause](../../yaml/README.md#only-and-except-simplified) +clause](../../yaml/README.md#onlyexcept-basic) to ensure our deployments only happen when we push to the master branch. Now, since the steps defined in `.gitlab-ci.yml` require credentials to login diff --git a/doc/ci/examples/end_to_end_testing_webdriverio/index.md b/doc/ci/examples/end_to_end_testing_webdriverio/index.md index d7afe11f41f..bd221b7145e 100644 --- a/doc/ci/examples/end_to_end_testing_webdriverio/index.md +++ b/doc/ci/examples/end_to_end_testing_webdriverio/index.md @@ -139,7 +139,7 @@ new browser window interacting with your app as you specified. Which brings us to the exciting part: how do we run this in GitLab CI/CD? There are two things we need to do for this: -1. Set up [CI/CD jobs](../../yaml/README.md#jobs) that actually have a browser available. +1. Set up [CI/CD jobs](../../yaml/README.md#introduction) that actually have a browser available. 2. Update our WebdriverIO configuration to use those browsers to visit the review apps. For the scope of this article, we've defined an additional [CI/CD stage](../../yaml/README.md#stages) @@ -184,7 +184,7 @@ option as an argument to `npm run confidence-check` on the command line. However, we still need to tell WebdriverIO which browser is available for it to use. [GitLab CI/CD makes -a number of variables available](../../variables/README.html#predefined-variables-environment-variables) +a number of variables available](../../variables/README.html#predefined-environment-variables) with information about the current CI job. We can use this information to dynamically set up our WebdriverIO configuration according to the job that is running. More specifically, we can tell WebdriverIO what browser to execute the test on depending on the name of the currently running diff --git a/doc/ci/junit_test_reports.md b/doc/ci/junit_test_reports.md index cf18c6d9660..d03c0b68daf 100644 --- a/doc/ci/junit_test_reports.md +++ b/doc/ci/junit_test_reports.md @@ -113,8 +113,8 @@ There are a few tools that can produce JUnit reports in Java. In the following example, `gradle` is used to generate the test reports. If there are multiple test tasks defined, `gradle` will generate multiple -directories under `build/test-results/`. In that case, you can leverage regex -matching by defining the following path: `build/test-results/test/TEST-*.xml`: +directories under `build/test-results/`. In that case, you can leverage glob +matching by defining the following path: `build/test-results/test/**/TEST-*.xml`: ```yaml java: @@ -123,7 +123,7 @@ java: - gradle test artifacts: reports: - junit: build/test-results/test/TEST-*.xml + junit: build/test-results/test/**/TEST-*.xml ``` #### Maven diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 55ecc0dccd1..4d15d58cb40 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -573,7 +573,7 @@ If any of the conditions in `variables` evaluates to truth when using `only`, a new job is going to be created. If any of the expressions evaluates to truth when `except` is being used, a job is not going to be created. -This follows usual rules for [`only` / `except` policies][builds-policies]. +This follows usual rules for [`only` / `except` policies](../yaml/README.md#onlyexcept-advanced). ### Supported syntax @@ -639,7 +639,6 @@ Below you can find supported syntax reference: [protected tags]: ../../user/project/protected_tags.md [shellexecutors]: https://docs.gitlab.com/runner/executors/ [triggered]: ../triggers/README.md -[builds-policies]: ../yaml/README.md#only-and-except-complex [gitlab-deploy-token]: ../../user/project/deploy_tokens/index.md#gitlab-deploy-token [registry]: ../../user/project/container_registry.md [dependent-repositories]: ../../user/project/new_ci_build_permissions_model.md#dependent-repositories diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index e1045864db7..9eb694a2c64 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -423,7 +423,7 @@ If you use multiple keys under `only` or `except`, they act as an AND. The logic #### `only:refs`/`except:refs` The `refs` strategy can take the same values as the -[simplified only/except configuration](#only-and-except-simplified). +[simplified only/except configuration](#onlyexcept-basic). In the example below, the `deploy` job is going to be created only when the pipeline has been [scheduled][schedules] or runs for the `master` branch: diff --git a/doc/development/code_review.md b/doc/development/code_review.md index f115045dbb7..b1a32e0ed26 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -20,7 +20,7 @@ importance of involving reviewer(s) in the section on the responsibility of the If you need some guidance (e.g. it's your first merge request), feel free to ask one of the [Merge request coaches][team]. -If you need assistance with security scans or comments, feel free to include the +If you need assistance with security scans or comments, feel free to include the Security Team (`@gitlab-com/gl-security`) in the review. The `danger-review` CI job will randomly pick a reviewer and a maintainer for @@ -58,12 +58,7 @@ from teams other than your own. #### Security requirements - 1. If your merge request is processing, storing, or transferring any kind of [RED or ORANGE data](https://docs.google.com/document/d/15eNKGA3zyZazsJMldqTBFbYMnVUSQSpU14lo22JMZQY/edit) (this is a confidential document), it must be - **approved by a [Security Engineer][team]**. - 1. If your merge request involves implementing, utilizing, or is otherwise related to any type of authentication, authorization, or session handling mechanism, it must be - **approved by a [Security Engineer][team]**. - 1. If your merge request has a goal which requires a cryptographic function such as: confidentiality, integrity, authentication, or non-repudiation, it must be - **approved by a [Security Engineer][team]**. +View the updated documentation regarding [internal application security reviews](https://about.gitlab.com/handbook/engineering/security/index.html#internal-application-security-reviews) for **when** and **how** to request a security review. ### The responsibility of the merge request author @@ -138,10 +133,10 @@ as a domain expert and/or reviewer, it is recommended that they are not also pic as the maintainer to ultimately approve and merge it. Try to review in a timely manner; doing so allows everyone involved in the merge -request to iterate faster as the context is fresh in memory. Further, this +request to iterate faster as the context is fresh in memory. Further, this improves contributors' experiences significantly. Reviewers should aim to review -within two working days from the date they were assigned the merge request. If -you don't think you'll be able to review a merge request within that time, let +within two working days from the date they were assigned the merge request. If +you don't think you'll be able to review a merge request within that time, let the author know as soon as possible. When the author of the merge request has not heard anything after two days, a new reviewer should be assigned. @@ -151,7 +146,7 @@ required approvers. Maintainers must check before merging if the merge request is introducing new vulnerabilities, by inspecting the list in the Merge Request [Security Widget](https://docs.gitlab.com/ee/user/project/merge_requests/#security-reports-ultimate). -When in doubt, a [Security Engineer][team] can be involved. The list of detected +When in doubt, a [Security Engineer][team] can be involved. The list of detected vulnerabilities must be either empty or containing: - dismissed vulnerabilities in case of false positives diff --git a/doc/development/documentation/feature-change-workflow.md b/doc/development/documentation/feature-change-workflow.md index 3f31fe5ca19..1f68b6a6a70 100644 --- a/doc/development/documentation/feature-change-workflow.md +++ b/doc/development/documentation/feature-change-workflow.md @@ -78,7 +78,7 @@ For issues requiring any new or updated documentation, the Product Manager (PM) must: - Add the `Documentation` label. -- Confirm or add the [documentation requirements](#documentation-requirements). +- Confirm or add the [documentation requirements](#documentation-requirements-in-feature-issues). - Ensure the issue contains any new or updated feature name, overview/description, and use cases, as required per the [documentation structure and template](structure.md), when applicable. diff --git a/doc/development/testing_guide/end_to_end_tests.md b/doc/development/testing_guide/end_to_end_tests.md index 7010250b33c..9837ea515a3 100644 --- a/doc/development/testing_guide/end_to_end_tests.md +++ b/doc/development/testing_guide/end_to_end_tests.md @@ -27,10 +27,15 @@ Results are reported in the `#qa-staging` Slack channel. ### Testing code in merge requests +#### Using the `package-and-qa` job + It is possible to run end-to-end tests for a merge request, eventually being run in a pipeline in the [`gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/) project, -by triggering the `package-and-qa` manual action in the `test` stage (which should -be present in a merge request widget, unless the merge request comes from a fork). +by triggering the `package-and-qa` manual action in the `test` stage (not +available for forks). + +**This runs end-to-end tests against a custom Omnibus package built from your +merge request's changes.** Manual action that starts end-to-end tests is also available in merge requests in [Omnibus GitLab][omnibus-gitlab]. @@ -85,7 +90,25 @@ subgraph gitlab-qa pipeline 1. The result of the [GitLab QA pipeline][gitlab-qa-pipelines] is being propagated upstream, through Omnibus, back to the CE / EE merge request. -#### How do I write tests? +#### Using the `review-qa-all` jobs + +On every pipeline during the `test` stage, the `review-qa-smoke` job is +automatically started: it runs the QA smoke suite against the +[Review App][review-apps]. + +You can also manually start the `review-qa-all`: it runs the full QA suite +against the [Review App][review-apps]. + +**This runs end-to-end tests against a Review App based on [the official GitLab +Helm chart][helm-chart], itself deployed with custom +[Cloud Native components][cng] built from your merge request's changes.** + +See [Review Apps][review-apps] for more details about Review Apps. + +[helm-chart]: https://gitlab.com/charts/gitlab/ +[cng]: https://gitlab.com/gitlab-org/build/CNG + +## How do I write tests? In order to write new tests, you first need to learn more about GitLab QA architecture. See the [documentation about it][gitlab-qa-architecture]. @@ -105,9 +128,11 @@ you can find an issue you would like to work on in [omnibus-gitlab]: https://gitlab.com/gitlab-org/omnibus-gitlab [gitlab-qa]: https://gitlab.com/gitlab-org/gitlab-qa +[gitlab-qa-pipelines]: https://gitlab.com/gitlab-org/gitlab-qa/pipelines [gitlab-qa-readme]: https://gitlab.com/gitlab-org/gitlab-qa/tree/master/README.md [quality-nightly-pipelines]: https://gitlab.com/gitlab-org/quality/nightly/pipelines [quality-staging-pipelines]: https://gitlab.com/gitlab-org/quality/staging/pipelines +[review-apps]: ./review_apps.md [gitlab-qa-architecture]: https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/architecture.md [gitlab-qa-issues]: https://gitlab.com/gitlab-org/gitlab-qa/issues?label_name%5B%5D=new+scenario [gitlab-ce-issues]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name[]=QA&label_name[]=test diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md index fda3ff57316..ffc71051377 100644 --- a/doc/development/testing_guide/review_apps.md +++ b/doc/development/testing_guide/review_apps.md @@ -90,8 +90,8 @@ subgraph GCP `gitlab-review-apps` project ## QA runs On every [pipeline][gitlab-pipeline] during the `test` stage, the -`review-qa-smoke` job is automatically started: it runs the smoke QA suite. -You can also manually start the `review-qa-all`: it runs the full QA suite. +`review-qa-smoke` job is automatically started: it runs the QA smoke suite. +You can also manually start the `review-qa-all`: it runs the QA full suite. Note that both jobs first wait for the `review-deploy` job to be finished. diff --git a/doc/development/testing_guide/smoke.md b/doc/development/testing_guide/smoke.md index 3360031c220..30d861d7d68 100644 --- a/doc/development/testing_guide/smoke.md +++ b/doc/development/testing_guide/smoke.md @@ -7,13 +7,19 @@ functionality is working. Currently, our suite consists of this basic functionality coverage: -- User Login (Standard Auth) -- Project Creation -- Issue Creation -- Merge Request Creation +- User standard authentication +- SSH Key creation and addition to a user +- Project simple creation +- Project creation with Auto-DevOps enabled +- Issue creation +- Merge Request creation +- Snippet creation Smoke tests have the `:smoke` RSpec metadata. +See [End-to-end Testing](./end_to_end_tests.md) for more details about +end-to-end tests. + --- [Return to Testing documentation](index.md) diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md index 5d46833a1e2..352651fe91b 100644 --- a/doc/development/testing_guide/testing_levels.md +++ b/doc/development/testing_guide/testing_levels.md @@ -160,7 +160,7 @@ Every new feature should come with a [test plan]. > See [end-to-end tests](end_to_end_tests.md) for more information. Note that `qa/spec` contains unit tests of the QA framework itself, not to be -confused with the application's [unit tests](#unit-tests) or +confused with the application's [unit tests](#unit-tests) or [end-to-end tests](#black-box-tests-at-the-system-level-aka-end-to-end-tests). [multiple pieces]: ../architecture.md#components @@ -234,6 +234,8 @@ you should write an integration test using Jasmine. [big]: https://twitter.com/timbray/status/822470746773409794 [picture]: https://twitter.com/withzombies/status/829716565834752000 [tests-cost]: https://medium.com/table-xi/high-cost-tests-and-high-value-tests-a86e27a54df#.2ulyh3a4e +[RSpec]: https://github.com/rspec/rspec-rails#feature-specs +[Capybara]: https://github.com/teamcapybara/capybara --- diff --git a/doc/development/ux_guide/users.md b/doc/development/ux_guide/users.md index 11bac11257c..3aecbbffd73 100644 --- a/doc/development/ux_guide/users.md +++ b/doc/development/ux_guide/users.md @@ -1,5 +1,5 @@ --- -redirect_to: 'https://design.gitlab.com/getting-started/personas/' +redirect_to: 'https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/' --- -The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/). +This document was moved to [another location](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/). diff --git a/doc/gitlab-basics/add-merge-request.md b/doc/gitlab-basics/add-merge-request.md index 5cc014419ad..7bb2e014738 100644 --- a/doc/gitlab-basics/add-merge-request.md +++ b/doc/gitlab-basics/add-merge-request.md @@ -8,7 +8,7 @@ request. For more information, check the --- 1. Before you start, you should have already [created a branch](create-branch.md) - and [pushed your changes](basic-git-commands.md) to GitLab. + and [pushed your changes](start-using-git.md#send-changes-to-gitlabcom) to GitLab. 1. Go to the project where you'd like to merge your changes and click on the **Merge requests** tab. 1. Click on **New merge request** on the right side of the screen. diff --git a/doc/gitlab-basics/create-group.md b/doc/gitlab-basics/create-group.md index 985a52d88f5..8c0d3561882 100644 --- a/doc/gitlab-basics/create-group.md +++ b/doc/gitlab-basics/create-group.md @@ -1,2 +1,5 @@ +--- +redirect_to: '../user/group/index.md#create-a-new-group' +--- This document was moved to [another location](../user/group/index.md#create-a-new-group). diff --git a/doc/gitlab-basics/create-issue.md b/doc/gitlab-basics/create-issue.md index abb163dbf18..818a03a6f02 100644 --- a/doc/gitlab-basics/create-issue.md +++ b/doc/gitlab-basics/create-issue.md @@ -1,2 +1,5 @@ +--- +redirect_to: '../user/project/issues/index.md#new-issue' +--- This document was moved to [another location](../user/project/issues/index.md#new-issue). diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md index 3d4259ab7d3..3e99496d531 100644 --- a/doc/gitlab-basics/create-project.md +++ b/doc/gitlab-basics/create-project.md @@ -42,7 +42,9 @@ Project templates can pre-populate your project with necessary files to get you There are two types of project templates: -- [Built-in templates](#built-in-templates), sourced from the [`project-templates`](https://gitlab.com/gitlab-org/project-templates) group. +- [Built-in templates](#built-in-templates), sourced from the following groups: + - [`project-templates`](https://gitlab.com/gitlab-org/project-templates) + - [`pages`](https://gitlab.com/pages) - [Custom project templates](#custom-project-templates-premium-only), for custom templates configured by GitLab administrators and users. ### Built-in templates @@ -50,7 +52,7 @@ There are two types of project templates: Built-in templates are project templates that are: - Developed and maintained in the - [`project-templates`](https://gitlab.com/gitlab-org/project-templates) group. + [`project-templates`](https://gitlab.com/gitlab-org/project-templates) and [`pages`](https://gitlab.com/pages) groups. - Released with GitLab. To use a built-in template on the **New project** page: @@ -64,7 +66,7 @@ To use a built-in template on the **New project** page: TIP: **Tip:** You can improve the existing built-in templates or contribute new ones on the -[`project-templates`](https://gitlab.com/gitlab-org/project-templates) group. +[`project-templates`](https://gitlab.com/gitlab-org/project-templates) and [`pages`](https://gitlab.com/pages) groups. ### Custom project templates **[PREMIUM ONLY]** diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md index 2fcc9b90157..d02aa24cd85 100644 --- a/doc/install/aws/index.md +++ b/doc/install/aws/index.md @@ -55,6 +55,8 @@ Here's a list of the AWS services we will use, with links to pricing information - **ElastiCache**: An in-memory cache environment will be used to provide a High Availability Redis configuration. See the [Amazon ElastiCache pricing](https://aws.amazon.com/elasticache/pricing/). + +NOTE: **Note:** Please note that while we will be using EBS for storage, we do not recommend using EFS as it may negatively impact GitLab's performance. You can review the [relevant documentation](../../administration/high_availability/nfs.md#avoid-using-awss-elastic-file-system-efs) for more details. ## Creating an IAM EC2 instance role and profile To minimize the permissions of the user, we'll create a new [IAM](https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html) diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md index 69bbd05c367..2932c884d04 100644 --- a/doc/integration/omniauth.md +++ b/doc/integration/omniauth.md @@ -256,7 +256,7 @@ gitlab_rails['omniauth_enabled'] = false You can enable profile syncing from selected OmniAuth providers and for all or for specific user information. -When authenticating using LDAP, the user's email is always synced. +When authenticating using LDAP, the user's name and email are always synced. ```ruby gitlab_rails['sync_profile_from_provider'] = ['twitter', 'google_oauth2'] diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index a1825581ebf..22011cc6967 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -20,7 +20,7 @@ From now on, every existing project and newly created ones that don't have a `.gitlab-ci.yml`, will use the Auto DevOps pipelines. If you want to disable it for a specific project, you can do so in -[its settings](../../../topics/autodevops/index.md##enablingdisabling-auto-devops). +[its settings](../../../topics/autodevops/index.md#enablingdisabling-auto-devops). ## Maximum artifacts size **[CORE ONLY]** diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md index cf0dc51ea23..23b9604a456 100644 --- a/doc/user/discussions/index.md +++ b/doc/user/discussions/index.md @@ -11,7 +11,7 @@ You can leave a comment in the following places: - commit diffs There are standard comments, and you also have the option to create a comment -in the form of a threaded discussion. A comment can also be [turned into a discussion](#start-a-discussion-by-replying-to-a-non-discussion-comment) +in the form of a threaded discussion. A comment can also be [turned into a discussion](#start-a-discussion-by-replying-to-a-standard-comment) when it receives a reply. The comment area supports [Markdown] and [quick actions]. You can edit your own diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md index 5dc798fd8d3..2fb6cec55fa 100644 --- a/doc/user/gitlab_com/index.md +++ b/doc/user/gitlab_com/index.md @@ -71,6 +71,14 @@ or over the size limit, you can [reduce your repository size with Git](../projec | ----------- | ----------------- | ------------- | | Repository size including LFS | 10G | Unlimited | +## IP range + +GitLab.com, CI/CD, and related services are deployed into Google Cloud Platform (GCP). Any +IP based firewall can be configured by looking up all +[IP address ranges or CIDR blocks for GCP](https://cloud.google.com/compute/docs/faq#where_can_i_find_product_name_short_ip_ranges). + +[Static endpoints](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/5071) are being considered. + ## Shared Runners Shared Runners on GitLab.com run in [autoscale mode] and powered by diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md index e67795b9bae..f6bb342de43 100644 --- a/doc/user/group/clusters/index.md +++ b/doc/user/group/clusters/index.md @@ -28,6 +28,7 @@ deployments. | [Helm Tiller](https://docs.helm.sh) | 11.6+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. | n/a | | [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress) | 11.6+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps](../../../topics/autodevops/index.md) or deploy your own web apps. | [stable/nginx-ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress) | | [Cert-Manager](https://docs.cert-manager.io/en/latest/) | 11.6+ | Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert-Manager on your cluster will issue a certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that certificates are valid and up-to-date. | [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager) | +| [GitLab Runner](https://docs.gitlab.com/runner/) | 11.10+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](../../../ci/README.md), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) | NOTE: **Note:** Some [cluster @@ -35,8 +36,6 @@ applications](../../project/clusters/index.md#installing-applications) are installable only for a project-level cluster. Support for installing these applications in a group-level cluster is planned for future releases. For updates, see: -- Support installing [Runner in group-level - clusters](https://gitlab.com/gitlab-org/gitlab-ce/issues/51988) - Support installing [JupyterHub in group-level clusters](https://gitlab.com/gitlab-org/gitlab-ce/issues/51989) - Support installing [Prometheus in group-level diff --git a/doc/user/index.md b/doc/user/index.md index b84879601ff..d408504249e 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -36,34 +36,34 @@ To get familiar with the concepts needed to develop code on GitLab, read the fol GitLab is a Git-based platform that integrates a great number of essential tools for software development and deployment, and project management: -- Hosting code in repositories with version control +- Hosting code in repositories with version control. - Tracking proposals for new implementations, bug reports, and feedback with a - fully featured [Issue Tracker](project/issues/index.md#issue-tracker) -- Organizing and prioritizing with [Issue Boards](project/issues/index.md#issue-boards) + fully featured [Issue Tracker](project/issues/index.md#issue-tracker). +- Organizing and prioritizing with [Issue Boards](project/issues/index.md#issue-board). - Reviewing code in [Merge Requests](project/merge_requests/index.md) with live-preview changes per - branch with [Review Apps](../ci/review_apps/index.md) -- Building, testing and deploying with built-in [Continuous Integration](../ci/README.md) -- Deploying personal and professional static websites with [GitLab Pages](project/pages/index.md) -- Integrating with Docker by using [GitLab Container Registry](project/container_registry.md) -- Tracking the development lifecycle by usingn [GitLab Cycle Analytics](project/cycle_analytics.md) + branch with [Review Apps](../ci/review_apps/index.md). +- Building, testing, and deploying with built-in [Continuous Integration](../ci/README.md). +- Deploying personal and professional static websites with [GitLab Pages](project/pages/index.md). +- Integrating with Docker by using [GitLab Container Registry](project/container_registry.md). +- Tracking the development lifecycle by using [GitLab Cycle Analytics](project/cycle_analytics.md). With GitLab Enterprise Edition, you can also: -- Provide support with [Service Desk](https://docs.gitlab.com/ee/user/project/service_desk.html) +- Provide support with [Service Desk](https://docs.gitlab.com/ee/user/project/service_desk.html). - Improve collaboration with [Merge Request Approvals](https://docs.gitlab.com/ee/user/project/merge_requests/index.html#merge-request-approvals), [Multiple Assignees for Issues](https://docs.gitlab.com/ee/user/project/issues/multiple_assignees_for_issues.html), - and [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards) -- Create formal relationships between issues with [Related Issues](https://docs.gitlab.com/ee/user/project/issues/related_issues.html) + and [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards-starter). +- Create formal relationships between issues with [Related Issues](https://docs.gitlab.com/ee/user/project/issues/related_issues.html). - Use [Burndown Charts](https://docs.gitlab.com/ee/user/project/milestones/burndown_charts.html) to track progress during a sprint or while working on a new version of their software. -- Leverage [Elasticsearch](https://docs.gitlab.com/ee/integration/elasticsearch.html) with [Advanced Global Search](https://docs.gitlab.com/ee/user/search/advanced_global_search.html) and [Advanced Syntax Search](https://docs.gitlab.com/ee/user/search/advanced_search_syntax.html) for faster, more advanced code search across your entire GitLab instance -- [Authenticate users with Kerberos](https://docs.gitlab.com/ee/integration/kerberos.html) +- Leverage [Elasticsearch](https://docs.gitlab.com/ee/integration/elasticsearch.html) with [Advanced Global Search](https://docs.gitlab.com/ee/user/search/advanced_global_search.html) and [Advanced Syntax Search](https://docs.gitlab.com/ee/user/search/advanced_search_syntax.html) for faster, more advanced code search across your entire GitLab instance. +- [Authenticate users with Kerberos](https://docs.gitlab.com/ee/integration/kerberos.html). - [Mirror a repository](https://docs.gitlab.com/ee/workflow/repository_mirroring.html) from elsewhere on your local server. -- [Export issues as CSV](https://docs.gitlab.com/ee/user/project/issues/csv_export.html) -- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipeline Graphs](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html) -- [Lock files](https://docs.gitlab.com/ee/user/project/file_lock.html) to prevent conflicts -- View the current health and status of each CI environment running on Kubernetes with [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html) -- Leverage continuous delivery method with [Canary Deployments](https://docs.gitlab.com/ee/user/project/canary_deployments.html) +- [Export issues as CSV](https://docs.gitlab.com/ee/user/project/issues/csv_export.html). +- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipelines](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html). +- [Lock files](https://docs.gitlab.com/ee/user/project/file_lock.html) to prevent conflicts. +- View the current health and status of each CI environment running on Kubernetes with [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html). +- Leverage continuous delivery method with [Canary Deployments](https://docs.gitlab.com/ee/user/project/canary_deployments.html). You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, Trello, @@ -125,7 +125,7 @@ merge requests, code snippets, and commits. When performing inline reviews to implementations to your codebase through merge requests you can -gather feedback through [resolvable discussions](discussions/index.md#resolvable-discussions). +gather feedback through [resolvable discussions](discussions/index.md#resolvable-comments-and-discussions). ### GitLab Flavored Markdown (GFM) diff --git a/doc/user/markdown.md b/doc/user/markdown.md index a7a87773eec..d8bc3a9187e 100644 --- a/doc/user/markdown.md +++ b/doc/user/markdown.md @@ -288,15 +288,15 @@ On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/he Ubuntu 18.04 (like many modern Linux distros) has this font installed by default. ``` -Sometimes you want to <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/monkey.png" width="20px" height="20px"> around a bit and add some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/star2.png" width="20px" height="20px"> to your <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/speech_balloon.png" width="20px" height="20px">. Well we have a gift for you: +Sometimes you want to <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/monkey.png" width="20px" height="20px"> around a bit and add some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/star2.png" width="20px" height="20px"> to your <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/speech_balloon.png" width="20px" height="20px">. Well we have a gift for you: -<img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/zap.png" width="20px" height="20px">You can use emoji anywhere GFM is supported. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/v.png" width="20px" height="20px"> +<img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/zap.png" width="20px" height="20px">You can use emoji anywhere GFM is supported. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/v.png" width="20px" height="20px"> -You can use it to point out a <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/bug.png" width="20px" height="20px"> or warn about <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/speak_no_evil.png" width="20px" height="20px"> patches. And if someone improves your really <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/snail.png" width="20px" height="20px"> code, send them some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/birthday.png" width="20px" height="20px">. People will <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/heart.png" width="20px" height="20px"> you for that. +You can use it to point out a <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/bug.png" width="20px" height="20px"> or warn about <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/speak_no_evil.png" width="20px" height="20px"> patches. And if someone improves your really <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/snail.png" width="20px" height="20px"> code, send them some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/birthday.png" width="20px" height="20px">. People will <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/heart.png" width="20px" height="20px"> you for that. -If you are new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/fearful.png" width="20px" height="20px">. You can easily join the emoji <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/family.png" width="20px" height="20px">. All you need to do is to look up one of the supported codes. +If you are new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/fearful.png" width="20px" height="20px">. You can easily join the emoji <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/family.png" width="20px" height="20px">. All you need to do is to look up one of the supported codes. -Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/thumbsup.png" width="20px" height="20px"> +Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/public/-/emojis/1/thumbsup.png" width="20px" height="20px"> Most emoji are natively supported on macOS, Windows, iOS, Android and will fallback to image-based emoji where there is lack of support. diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 44b9e5cccb5..7fde27b3d22 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -69,7 +69,7 @@ new Kubernetes cluster to your project: - **Number of nodes** - Enter the number of nodes you wish the cluster to have. - **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types) of the Virtual Machine instance that the cluster will be based on. - - **RBAC-enabled cluster** - Leave this checked if using default GKE creation options, see the [RBAC section](#role-based-access-control-rbac-core-only) for more information. + - **RBAC-enabled cluster** - Leave this checked if using default GKE creation options, see the [RBAC section](#role-based-access-control-rbac) for more information. 1. Finally, click the **Create Kubernetes cluster** button. After a couple of minutes, your cluster will be ready to go. You can now proceed @@ -101,14 +101,20 @@ To add an existing Kubernetes cluster to your project: It's the URL that GitLab uses to access the Kubernetes API. Kubernetes exposes several APIs, we want the "base" URL that is common to all of them, e.g., `https://kubernetes.example.com` rather than `https://kubernetes.example.com/api/v1`. + + Get the API URL by running this command: + + ```sh + kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}' + ``` - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the EKS cluster. We will use the certificate created by default. - - List the secrets with `kubectl get secrets`, and one should named similar to + - List the secrets with `kubectl get secrets`, and one should named similar to `default-token-xxxxx`. Copy that token name for use below. - - Get the certificate by running this command: + - Get the certificate by running this command: - ```sh - kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode - ``` + ```sh + kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode + ``` - **Token** - GitLab authenticates against Kubernetes using service tokens, which are scoped to a particular `namespace`. @@ -124,23 +130,7 @@ To add an existing Kubernetes cluster to your project: metadata: name: gitlab-admin namespace: kube-system - ``` - - 2. Apply the service account to your cluster: - - ```bash - kubectl apply -f gitlab-admin-service-account.yaml - ``` - - Output: - - ```bash - serviceaccount "gitlab-admin" created - ``` - - 3. Create a file called `gitlab-admin-cluster-role-binding.yaml` with contents: - - ```yaml + --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: @@ -155,41 +145,42 @@ To add an existing Kubernetes cluster to your project: namespace: kube-system ``` - 4. Apply the cluster role binding to your cluster: + 1. Apply the service account and cluster role binding to your cluster: ```bash - kubectl apply -f gitlab-admin-cluster-role-binding.yaml + kubectl apply -f gitlab-admin-service-account.yaml ``` Output: ```bash + serviceaccount "gitlab-admin" created clusterrolebinding "gitlab-admin" created ``` - 5. Retrieve the token for the `gitlab-admin` service account: + 1. Retrieve the token for the `gitlab-admin` service account: ```bash kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}') ``` - Copy the `<authentication_token>` value from the output: + Copy the `<authentication_token>` value from the output: - ```yaml - Name: gitlab-admin-token-b5zv4 - Namespace: kube-system - Labels: <none> - Annotations: kubernetes.io/service-account.name=gitlab-admin - kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8 + ```yaml + Name: gitlab-admin-token-b5zv4 + Namespace: kube-system + Labels: <none> + Annotations: kubernetes.io/service-account.name=gitlab-admin + kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8 - Type: kubernetes.io/service-account-token + Type: kubernetes.io/service-account-token - Data - ==== - ca.crt: 1025 bytes - namespace: 11 bytes - token: <authentication_token> - ``` + Data + ==== + ca.crt: 1025 bytes + namespace: 11 bytes + token: <authentication_token> + ``` NOTE: **Note:** For GKE clusters, you will need the @@ -212,14 +203,6 @@ To add an existing Kubernetes cluster to your project: After a couple of minutes, your cluster will be ready to go. You can now proceed to install some [pre-defined applications](#installing-applications). -To determine the: - -- API URL, run `kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'`. -- Token: - 1. List the secrets by running: `kubectl get secrets`. Note the name of the secret you need the token for. - 1. Get the token for the appropriate secret by running: `kubectl get secret <SECRET_NAME> -o jsonpath="{['data']['token']}" | base64 --decode`. -- CA certificate, run `kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode`. - ## Security implications CAUTION: **Important:** @@ -360,8 +343,8 @@ by GitLab before installing any of the applications. | [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. | [stable/nginx-ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress) | | [Cert-Manager](https://docs.cert-manager.io/en/latest/) | 11.6+ | Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert-Manager on your cluster will issue a certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that certificates are valid and up-to-date. | [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager) | | [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | [stable/prometheus](https://github.com/helm/charts/tree/master/stable/prometheus) | -| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) | -| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use a [custom Jupyter image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) that installs additional useful packages on top of the base Jupyter. Authentication will be enabled only for [project members](../members/index.md) with [Developer or higher](../../permissions.md) access to the project. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found in [our Nurtch documentation](runbooks/index.md#nurtch-executable-runbooks). | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) | +| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](../../../ci/README.md), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) | +| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use a [custom Jupyter image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) that installs additional useful packages on top of the base Jupyter. Authentication will be enabled only for [project members](../members/index.md) with [Developer or higher](../../permissions.md) access to the project. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found in [our Nurtch documentation](runbooks/index.md#nurtch-executable-runbooks). Note that Ingress must be installed and have an IP address assigned before JupyterHub can be installed. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) | | [Knative](https://cloud.google.com/knative) | 11.5+ | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as `<program_name>.<kubernetes_namespace>.<domain_name>`. This will require your kubernetes cluster to have [RBAC enabled](#role-based-access-control-rbac). | [knative/knative](https://storage.googleapis.com/triggermesh-charts) With the exception of Knative, the applications will be installed in a dedicated diff --git a/doc/user/project/index.md b/doc/user/project/index.md index 4148310dc98..4d19464cb7a 100644 --- a/doc/user/project/index.md +++ b/doc/user/project/index.md @@ -17,7 +17,7 @@ When you create a project in GitLab, you'll have access to a large number of - [Issue tracker](issues/index.md): Discuss implementations with your team within issues - [Issue Boards](issue_board.md): Organize and prioritize your workflow - - [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards): Allow your teams to create their own workflows (Issue Boards) for the same project **[STARTER]** + - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **[STARTER]** - [Repositories](repository/index.md): Host your code in a fully integrated platform - [Branches](repository/branches/index.md): use Git branching strategies to diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md index 66168080087..ca19ce4d328 100644 --- a/doc/user/project/issue_board.md +++ b/doc/user/project/issue_board.md @@ -28,11 +28,11 @@ Issue Boards** (version introduced in GitLab 8.11 - August 2016). ### Advanced features of Issue Boards With [GitLab Starter](https://about.gitlab.com/pricing/), you can create -[multiple issue boards](#multiple-issue-boards) for a given project. **[STARTER]** +[multiple issue boards](#multiple-issue-boards-starter) for a given project. **[STARTER]** With [GitLab Premium](https://about.gitlab.com/pricing/), you can also create multiple -issue boards for your groups, and add lists for [assignees](#assignee-lists) and -[milestones](#milestone-lists). **[PREMIUM]** +issue boards for your groups, and add lists for [assignees](#assignee-lists-premium) and +[milestones](#milestone-lists-premium). **[PREMIUM]** Check all the [advanced features of Issue Boards](#gitlab-enterprise-features-for-issue-boards) below. @@ -97,7 +97,7 @@ If we have the labels "**backend**", "**frontend**", "**staging**", and ### Use cases for Multiple Issue Boards -With [Multiple Issue Boards](#multiple-issue-boards), available only in +With [Multiple Issue Boards](#multiple-issue-boards-starter), available only in [GitLab Enterprise Edition](https://about.gitlab.com/pricing/), each team can have their own board to organize their workflow individually. @@ -220,7 +220,7 @@ Click the button at the top right to toggle focus mode on and off. In focus mode The top of each list indicates the sum of issue weights for the issues that belong to that list. This is useful when using boards for capacity allocation, -especially in combination with [assignee lists](#assignee-lists). +especially in combination with [assignee lists](#assignee-lists-premium). ![Issue Board summed weights](img/issue_board_summed_weights.png) diff --git a/doc/user/project/issues/confidential_issues.md b/doc/user/project/issues/confidential_issues.md index 8eada25234f..2c755e0fb4d 100644 --- a/doc/user/project/issues/confidential_issues.md +++ b/doc/user/project/issues/confidential_issues.md @@ -1,6 +1,6 @@ # Confidential issues -> [Introduced][ce-3282] in GitLab 8.6. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3282) in GitLab 8.6. Confidential issues are issues visible only to members of a project with [sufficient permissions](#permissions-and-access-to-confidential-issues). @@ -67,7 +67,7 @@ There is also an indicator on the sidebar denoting confidentiality. There are two kinds of level access for confidential issues. The general rule is that confidential issues are visible only to members of a project with at -least [Reporter access][permissions]. However, a guest user can also create +least [Reporter access](../../permissions.md#project-members-permissions). However, a guest user can also create confidential issues, but can only view the ones that they created themselves. Confidential issues are also hidden in search results for unprivileged users. @@ -77,6 +77,3 @@ project's search results respectively. | Maintainer access | Guest access | | :-----------: | :----------: | | ![Confidential issues search master](img/confidential_issues_search_master.png) | ![Confidential issues search guest](img/confidential_issues_search_guest.png) | - -[permissions]: ../../permissions.md#project -[ce-3282]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3282 diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md index 786d1c81b1b..ff5b1f2ce50 100644 --- a/doc/user/project/issues/crosslinking_issues.md +++ b/doc/user/project/issues/crosslinking_issues.md @@ -48,13 +48,12 @@ issues in merge requests. ## From Merge Requests -Mentioning issues in merge request comments work exactly the same way +Mentioning issues in merge request comments works exactly the same way as they do for [related issues](#from-related-issues). -When you mention an issue in a merge request description, you can either -[close the issue as soon as the merge request is merged](closing_issues.md#via-merge-request), -or simply link both issue and merge request as described in the -[closing issues documentation](closing_issues.md#from-related-issues). +When you mention an issue in a merge request description, it will simply +[link the issue and merge request together](#from-related-issues). Additionally, +you can also [set an issue to close as soon as the merge request is merged](closing_issues.md#via-merge-request). ![issue mentioned in MR](img/mention_in_merge_request.png) diff --git a/doc/user/project/issues/due_dates.md b/doc/user/project/issues/due_dates.md index 7972c14c1c4..987c16dfab6 100644 --- a/doc/user/project/issues/due_dates.md +++ b/doc/user/project/issues/due_dates.md @@ -1,11 +1,11 @@ # Due dates -> [Introduced][ce-3614] in GitLab 8.7. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3614) in GitLab 8.7. Please read through the [GitLab Issue Documentation](index.md) for an overview on GitLab Issues. Due dates can be used in issues to keep track of deadlines and make sure -features are shipped on time. Due dates require at least [Reporter permissions][permissions] +features are shipped on time. Due dates require at least [Reporter permissions](../../permissions.md#project-members-permissions) to be able to edit them. On the contrary, they can be seen by everybody. ## Setting a due date @@ -47,6 +47,3 @@ on the _Subscribe to calendar_ button on the following pages: GitLab header - on the **Project Issues** page - on the **Group Issues** page - -[ce-3614]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3614 -[permissions]: ../../permissions.md#project diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md index 907a305fe23..675c280a12a 100644 --- a/doc/user/project/issues/index.md +++ b/doc/user/project/issues/index.md @@ -109,7 +109,7 @@ issue within your team only, you can make that [issue confidential](confidential_issues.md). Even if your project is public, that issue will be preserved. The browser will respond with a 404 error whenever someone who is not a project -member with at least [Reporter level](../../permissions.md#project) tries to +member with at least [Reporter level](../../permissions.md#project-members-permissions) tries to access that issue's URL. Learn more about them on the [confidential issues documentation](confidential_issues.md). @@ -140,7 +140,7 @@ Read through the documentation for [Issue Boards](../issue_board.md) to find out more about this feature. With [GitLab Starter](https://about.gitlab.com/pricing/), you can also -create various boards per project with [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards). +create various boards per project with [Multiple Issue Boards](../issue_board.html#multiple-issue-boards-starter). ### Import Issues from CSV diff --git a/doc/user/project/pages/getting_started_part_four.md b/doc/user/project/pages/getting_started_part_four.md index 021139d486d..f552f60a07e 100644 --- a/doc/user/project/pages/getting_started_part_four.md +++ b/doc/user/project/pages/getting_started_part_four.md @@ -24,7 +24,7 @@ one for the first time.** [GitLab CI/CD](../../../ci/README.md) serves numerous purposes, to build, test, and deploy your app from GitLab through -[Continuous Integration, Continuous Delivery, and Continuous Deployment](../../../ci/introduction/index.md#introduction-to-continuous-methods) +[Continuous Integration, Continuous Delivery, and Continuous Deployment](../../../ci/introduction/index.md#introduction-to-cicd-methodologies) methods. You will need it to build your website with GitLab Pages, and deploy it to the Pages server. diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md index ccb0300e23e..39f14a1126f 100644 --- a/doc/user/project/pages/introduction.md +++ b/doc/user/project/pages/introduction.md @@ -152,7 +152,7 @@ Depending on how you plan to publish your website, the steps defined in the Be aware that Pages are by default branch/tag agnostic and their deployment relies solely on what you specify in `.gitlab-ci.yml`. If you don't limit the -`pages` job with the [`only` parameter](../../../ci/yaml/README.md#only-and-except-simplified), +`pages` job with the [`only` parameter](../../../ci/yaml/README.md#onlyexcept-basic), whenever a new commit is pushed to whatever branch or tag, the Pages will be overwritten. In the example below, we limit the Pages to be deployed whenever a commit is pushed only on the `master` branch: @@ -253,7 +253,7 @@ get you started. Remember that GitLab Pages are by default branch/tag agnostic and their deployment relies solely on what you specify in `.gitlab-ci.yml`. You can limit -the `pages` job with the [`only` parameter](../../../ci/yaml/README.md#only-and-except-simplified), +the `pages` job with the [`only` parameter](../../../ci/yaml/README.md#onlyexcept-basic), whenever a new commit is pushed to a branch that will be used specifically for your pages. diff --git a/doc/user/project/pipelines/schedules.md b/doc/user/project/pipelines/schedules.md index 07ce4f3f5da..2911a56cf67 100644 --- a/doc/user/project/pipelines/schedules.md +++ b/doc/user/project/pipelines/schedules.md @@ -59,7 +59,7 @@ GitLab CI so that they can be used in your `.gitlab-ci.yml` file. To configure that a job can be executed only when the pipeline has been scheduled (or the opposite), you can use -[only and except](../../../ci/yaml/README.md#only-and-except-simplified) configuration keywords. +[only and except](../../../ci/yaml/README.md#onlyexcept-basic) configuration keywords. ``` job:on-schedule: diff --git a/doc/user/snippets.md b/doc/user/snippets.md index 569bdc9e2d5..7b580a057f2 100644 --- a/doc/user/snippets.md +++ b/doc/user/snippets.md @@ -20,7 +20,7 @@ and private. See [Public access](../public_access/public_access.md) for more inf ## Project snippets Project snippets are always related to a specific project. -See [Project's features](project/index.md#projects-features) for more information. +See [Project features](project/index.md#project-features) for more information. ## Discover snippets diff --git a/doc/workflow/add-user/add-user.md b/doc/workflow/add-user/add-user.md index 35cc080d2b7..f1ec771dd9a 100644 --- a/doc/workflow/add-user/add-user.md +++ b/doc/workflow/add-user/add-user.md @@ -1 +1,5 @@ +--- +redirect_to: '../../user/project/members/index.md' +--- + This document was moved to [../../user/project/members/index.md](../../user/project/members/index.md) diff --git a/doc/workflow/authorization_for_merge_requests.md b/doc/workflow/authorization_for_merge_requests.md index 7bf80a3ad0d..8e43d340613 100644 --- a/doc/workflow/authorization_for_merge_requests.md +++ b/doc/workflow/authorization_for_merge_requests.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/merge_requests/authorization_for_merge_requests.md' +--- + This document was moved to [user/project/merge_requests/authorization_for_merge_requests](../user/project/merge_requests/authorization_for_merge_requests.md) diff --git a/doc/workflow/award_emoji.md b/doc/workflow/award_emoji.md index d74378cc564..02db97b8dd6 100644 --- a/doc/workflow/award_emoji.md +++ b/doc/workflow/award_emoji.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/award_emojis.md' +--- + This document was moved to [another location](../user/award_emojis.md). diff --git a/doc/workflow/cherry_pick_changes.md b/doc/workflow/cherry_pick_changes.md index 663ffd3f746..29c4f854416 100644 --- a/doc/workflow/cherry_pick_changes.md +++ b/doc/workflow/cherry_pick_changes.md @@ -1 +1,5 @@ -This document was moved to [user/project/merge_requests/cherry_pick_changes](../user/project/merge_requests/cherry_pick_changes.md). +--- +redirect_to: '../user/project/merge_requests/cherry_pick_changes.md' +--- + +This document was moved to [another location](../user/project/merge_requests/cherry_pick_changes.md). diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md index e0a445920b4..29da321ba46 100644 --- a/doc/workflow/importing/README.md +++ b/doc/workflow/importing/README.md @@ -1 +1,5 @@ +---
+redirect_to: '../../user/project/import/index.md'
+---
+
This document was moved to [another location](../../user/project/import/index.md).
diff --git a/doc/workflow/importing/import_projects_from_bitbucket.md b/doc/workflow/importing/import_projects_from_bitbucket.md index ec9a11f390e..a42ba7d4518 100644 --- a/doc/workflow/importing/import_projects_from_bitbucket.md +++ b/doc/workflow/importing/import_projects_from_bitbucket.md @@ -1 +1,5 @@ +---
+redirect_to: '../../user/project/import/bitbucket.md'
+---
+
This document was moved to [another location](../../user/project/import/bitbucket.md).
diff --git a/doc/workflow/importing/import_projects_from_fogbugz.md b/doc/workflow/importing/import_projects_from_fogbugz.md index 876eb0434f0..f5c791dc6de 100644 --- a/doc/workflow/importing/import_projects_from_fogbugz.md +++ b/doc/workflow/importing/import_projects_from_fogbugz.md @@ -1 +1,5 @@ +--- +redirect_to: '../../user/project/import/fogbugz.md' +--- + This document was moved to [another location](../../user/project/import/fogbugz.md). diff --git a/doc/workflow/importing/import_projects_from_gitea.md b/doc/workflow/importing/import_projects_from_gitea.md index 8b55b6c23eb..df053835b44 100644 --- a/doc/workflow/importing/import_projects_from_gitea.md +++ b/doc/workflow/importing/import_projects_from_gitea.md @@ -1 +1,5 @@ +--- +redirect_to: '../../user/project/import/gitea.md' +--- + This document was moved to [another location](../../user/project/import/gitea.md). diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index 72dfe5403c3..6397fcc74b8 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -1 +1,5 @@ +---
+redirect_to: '../../user/project/import/github.md'
+---
+
This document was moved to [another location](../../user/project/import/github.md).
diff --git a/doc/workflow/importing/import_projects_from_gitlab_com.md b/doc/workflow/importing/import_projects_from_gitlab_com.md index 3256088c014..135b9704df9 100644 --- a/doc/workflow/importing/import_projects_from_gitlab_com.md +++ b/doc/workflow/importing/import_projects_from_gitlab_com.md @@ -1 +1,5 @@ +--- +redirect_to: '../../user/project/import/gitlab_com.md' +--- + This document was moved to [another location](../../user/project/import/gitlab_com.md). diff --git a/doc/workflow/importing/migrating_from_svn.md b/doc/workflow/importing/migrating_from_svn.md index 32a75a6c6af..99f13d6354c 100644 --- a/doc/workflow/importing/migrating_from_svn.md +++ b/doc/workflow/importing/migrating_from_svn.md @@ -1 +1,5 @@ +--- +redirect_to: '../../user/project/import/svn.md' +--- + This document was moved to [another location](../../user/project/import/svn.md). diff --git a/doc/workflow/labels.md b/doc/workflow/labels.md index 5c09891dfdd..3d07d411dd4 100644 --- a/doc/workflow/labels.md +++ b/doc/workflow/labels.md @@ -1,3 +1,7 @@ +--- +redirect_to: '../user/project/labels.md' +--- + # Labels This document was moved to [user/project/labels.md](../user/project/labels.md). diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index dc6da1938f3..fd9f9b81bc9 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/merge_requests/index.md' +--- + This document was moved to [user/project/merge_requests/index.md](../user/project/merge_requests/index.md). diff --git a/doc/workflow/merge_when_build_succeeds.md b/doc/workflow/merge_when_build_succeeds.md index b4f6d6117de..41e6ff0cdd6 100644 --- a/doc/workflow/merge_when_build_succeeds.md +++ b/doc/workflow/merge_when_build_succeeds.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/merge_requests/merge_when_pipeline_succeeds.md' +--- + This document was moved to [merge_when_pipeline_succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md). diff --git a/doc/workflow/milestones.md b/doc/workflow/milestones.md index 69eb6b286b0..18dc15f7327 100644 --- a/doc/workflow/milestones.md +++ b/doc/workflow/milestones.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/milestones/index.md' +--- + This document was moved to [another location](../user/project/milestones/index.md). diff --git a/doc/workflow/project_features.md b/doc/workflow/project_features.md index feb88712f5a..f54afb768a1 100644 --- a/doc/workflow/project_features.md +++ b/doc/workflow/project_features.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/index.md' +--- + This document was moved to [../user/project/index.md](../user/project/index.md) diff --git a/doc/workflow/protected_branches.md b/doc/workflow/protected_branches.md index ced7d391ace..1bcac4a2de5 100644 --- a/doc/workflow/protected_branches.md +++ b/doc/workflow/protected_branches.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/protected_branches.md' +--- + This document was moved to [another location](../user/project/protected_branches.md). diff --git a/doc/workflow/revert_changes.md b/doc/workflow/revert_changes.md index cf1292253fc..15f199af703 100644 --- a/doc/workflow/revert_changes.md +++ b/doc/workflow/revert_changes.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/merge_requests/revert_changes.md' +--- + This document was moved to [user/project/merge_requests/revert_changes](../user/project/merge_requests/revert_changes.md). diff --git a/doc/workflow/share_projects_with_other_groups.md b/doc/workflow/share_projects_with_other_groups.md index 2eb4d24958a..c39cd78f32d 100644 --- a/doc/workflow/share_projects_with_other_groups.md +++ b/doc/workflow/share_projects_with_other_groups.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/members/share_project_with_groups.md' +--- + This document was moved to [../user/project/members/share_project_with_groups.md](../user/project/members/share_project_with_groups.md) diff --git a/doc/workflow/share_with_group.md b/doc/workflow/share_with_group.md index 2eb4d24958a..c39cd78f32d 100644 --- a/doc/workflow/share_with_group.md +++ b/doc/workflow/share_with_group.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/members/share_project_with_groups.md' +--- + This document was moved to [../user/project/members/share_project_with_groups.md](../user/project/members/share_project_with_groups.md) diff --git a/doc/workflow/web_editor.md b/doc/workflow/web_editor.md index 595c7da155b..2366372d984 100644 --- a/doc/workflow/web_editor.md +++ b/doc/workflow/web_editor.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/repository/web_editor.md' +--- + This document was moved to [user/project/repository/web_editor](../user/project/repository/web_editor.md). diff --git a/doc/workflow/wip_merge_requests.md b/doc/workflow/wip_merge_requests.md index abb8002f442..020455dcbdc 100644 --- a/doc/workflow/wip_merge_requests.md +++ b/doc/workflow/wip_merge_requests.md @@ -1 +1,5 @@ +--- +redirect_to: '../user/project/merge_requests/work_in_progress_merge_requests.md' +--- + This document was moved to [user/project/merge_requests/work_in_progress_merge_requests](../user/project/merge_requests/work_in_progress_merge_requests.md). diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 4764f8e1e19..5f8aca104aa 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -181,9 +181,10 @@ module Banzai title = object_link_title(object, matches) klass = reference_class(object_sym) - data = data_attributes_for(link_content || match, parent, object, - link_content: !!link_content, - link_reference: link_reference) + data_attributes = data_attributes_for(link_content || match, parent, object, + link_content: !!link_content, + link_reference: link_reference) + data = data_attribute(data_attributes) url = if matches.names.include?("url") && matches[:url] @@ -206,13 +207,13 @@ module Banzai def data_attributes_for(text, parent, object, link_content: false, link_reference: false) object_parent_type = parent.is_a?(Group) ? :group : :project - data_attribute( + { original: text, link: link_content, link_reference: link_reference, object_parent_type => parent.id, object_sym => object.id - ) + } end def object_link_text_extras(object, matches) diff --git a/lib/banzai/filter/merge_request_reference_filter.rb b/lib/banzai/filter/merge_request_reference_filter.rb index 7098767b583..f05902078dc 100644 --- a/lib/banzai/filter/merge_request_reference_filter.rb +++ b/lib/banzai/filter/merge_request_reference_filter.rb @@ -20,7 +20,9 @@ module Banzai end def object_link_title(object, matches) - object_link_commit_title(object, matches) || super + # The method will return `nil` if object is not a commit + # allowing for properly handling the extended MR Tooltip + object_link_commit_title(object, matches) end def object_link_text_extras(object, matches) @@ -53,6 +55,14 @@ module Banzai .includes(target_project: :namespace) end + def reference_class(object_sym, options = {}) + super(object_sym, tooltip: false) + end + + def data_attributes_for(text, parent, object, data = {}) + super.merge(project_path: parent.full_path, iid: object.iid, mr_title: object.title) + end + private def object_link_commit_title(object, matches) diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb index f38c5d57c44..09d1d79fefc 100644 --- a/lib/gitlab/auth/o_auth/user.rb +++ b/lib/gitlab/auth/o_auth/user.rb @@ -146,7 +146,6 @@ module Gitlab Gitlab::Auth::LDAP::Person.find_by_uid(auth_hash.uid, adapter) || Gitlab::Auth::LDAP::Person.find_by_email(auth_hash.uid, adapter) || Gitlab::Auth::LDAP::Person.find_by_dn(auth_hash.uid, adapter) - rescue Gitlab::Auth::LDAP::LDAPConnectionError nil end @@ -200,22 +199,19 @@ module Gitlab # Give preference to LDAP for sensitive information when creating a linked account if creating_linked_ldap_user? username = ldap_person.username.presence + name = ldap_person.name.presence email = ldap_person.email.first.presence end username ||= auth_hash.username + name ||= auth_hash.name email ||= auth_hash.email valid_username = ::Namespace.clean_path(username) - - uniquify = Uniquify.new - valid_username = uniquify.string(valid_username) { |s| !NamespacePathValidator.valid_path?(s) } - - name = auth_hash.name - name = valid_username if name.strip.empty? + valid_username = Uniquify.new.string(valid_username) { |s| !NamespacePathValidator.valid_path?(s) } { - name: name, + name: name.strip.presence || valid_username, username: valid_username, email: email, password: auth_hash.password, @@ -248,8 +244,9 @@ module Gitlab metadata.provider = auth_hash.provider end - if creating_linked_ldap_user? && gl_user.email == ldap_person.email.first - metadata.set_attribute_synced(:email, true) + if creating_linked_ldap_user? + metadata.set_attribute_synced(:name, true) if gl_user.name == ldap_person.name + metadata.set_attribute_synced(:email, true) if gl_user.email == ldap_person.email.first metadata.provider = ldap_person.provider end end diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb index d2b7ca015d4..ac65cf74808 100644 --- a/lib/gitlab/danger/helper.rb +++ b/lib/gitlab/danger/helper.rb @@ -108,7 +108,23 @@ module Gitlab %r{\A(ee/)?public/} => :frontend, %r{\A(ee/)?spec/(javascripts|frontend)/} => :frontend, %r{\A(ee/)?vendor/assets/} => :frontend, - %r{\A(jest\.config\.js|package\.json|yarn\.lock)\z} => :frontend, + %r{\Ascripts/frontend/} => :frontend, + %r{(\A|/)( + \.babelrc | + \.eslintignore | + \.eslintrc(\.yml)? | + \.nvmrc | + \.prettierignore | + \.prettierrc | + \.scss-lint.yml | + \.stylelintrc | + babel\.config\.js | + jest\.config\.js | + karma\.config\.js | + webpack\.config\.js | + package\.json | + yarn\.lock + )\z}x => :frontend, %r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend, %r{\A(ee/)?(bin|config|danger|generator_templates|lib|rubocop|scripts)/} => :backend, diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 88ff9fbceb4..8fac3621df9 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -318,6 +318,10 @@ module Gitlab parent_ids.size > 1 end + def gitaly_commit? + raw_commit.is_a?(Gitaly::GitCommit) + end + def tree_entry(path) return unless path.present? @@ -340,7 +344,7 @@ module Gitlab end def to_gitaly_commit - return raw_commit if raw_commit.is_a?(Gitaly::GitCommit) + return raw_commit if gitaly_commit? message_split = raw_commit.message.split("\n", 2) Gitaly::GitCommit.new( diff --git a/lib/gitlab/github_import/importer/pull_request_importer.rb b/lib/gitlab/github_import/importer/pull_request_importer.rb index 72451e5e01e..1b293ddc7c7 100644 --- a/lib/gitlab/github_import/importer/pull_request_importer.rb +++ b/lib/gitlab/github_import/importer/pull_request_importer.rb @@ -89,7 +89,7 @@ module Gitlab return if project.repository.branch_exists?(source_branch) - project.repository.add_branch(project.owner, source_branch, pull_request.source_branch_sha) + project.repository.add_branch(project.creator, source_branch, pull_request.source_branch_sha) rescue Gitlab::Git::CommandError => e Gitlab::Sentry.track_acceptable_exception(e, extra: { diff --git a/lib/gitlab/import/merge_request_helpers.rb b/lib/gitlab/import/merge_request_helpers.rb index fa3ff6c3f12..b3fe1fc0685 100644 --- a/lib/gitlab/import/merge_request_helpers.rb +++ b/lib/gitlab/import/merge_request_helpers.rb @@ -38,7 +38,6 @@ module Gitlab end # rubocop: enable CodeReuse/ActiveRecord - # rubocop: disable CodeReuse/ActiveRecord def insert_or_replace_git_data(merge_request, source_branch_sha, target_branch_sha, already_exists = false) # These fields are set so we can create the correct merge request # diffs. @@ -47,24 +46,21 @@ module Gitlab merge_request.keep_around_commit + # We force to recreate all diffs to replace all existing data + # We use `.all` as otherwise `dependent: :nullify` (the default) + # takes an effect + merge_request.merge_request_diffs.all.delete_all if already_exists + # MR diffs normally use an "after_save" hook to pull data from Git. # All of this happens in the transaction started by calling # create/save/etc. This in turn can lead to these transactions being # held open for much longer than necessary. To work around this we # first save the diff, then populate it. - diff = - if already_exists - merge_request.merge_request_diffs.take || - merge_request.merge_request_diffs.build - else - merge_request.merge_request_diffs.build - end - + diff = merge_request.merge_request_diffs.build diff.importing = true diff.save diff.save_git_content end - # rubocop: enable CodeReuse/ActiveRecord end end end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index f9c9ea4f936..75477c7cf18 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -84,6 +84,7 @@ module Gitlab projects: count(Project), projects_imported_from_github: count(Project.where(import_type: 'github')), projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)), + projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)), protected_branches: count(ProtectedBranch), releases: count(Release), remote_mirrors: count(RemoteMirror), diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 177bd189817..1a0224a44e6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1815,7 +1815,7 @@ msgstr "" msgid "ClusterIntegration|GitLab Runner" msgstr "" -msgid "ClusterIntegration|GitLab Runner connects to this project's repository and executes CI/CD jobs, pushing results back and deploying, applications to production." +msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production." msgstr "" msgid "ClusterIntegration|Google Cloud Platform project" diff --git a/package.json b/package.json index d830d83b963..b40436d057e 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "prettier-all": "node ./scripts/frontend/prettier.js check-all", "prettier-all-save": "node ./scripts/frontend/prettier.js save-all", "stylelint": "node node_modules/stylelint/bin/stylelint.js app/assets/stylesheets/**/*.* --custom-formatter node_modules/stylelint-error-string-formatter", + "stylelint-file": "node node_modules/stylelint/bin/stylelint.js", + "stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js", "test": "yarn jest && yarn karma", "webpack": "webpack --config config/webpack.config.js", "webpack-prod": "NODE_ENV=production webpack --config config/webpack.config.js" @@ -31,7 +33,7 @@ "@babel/preset-env": "^7.3.1", "@gitlab/csslab": "^1.8.0", "@gitlab/svgs": "^1.54.0", - "@gitlab/ui": "^2.3.0", + "@gitlab/ui": "^3.0.0", "apollo-boost": "^0.3.1", "apollo-client": "^2.5.1", "at.js": "^1.5.4", @@ -169,13 +171,15 @@ "karma-mocha-reporter": "^2.2.5", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^4.0.0-beta.0", + "md5": "^2.2.1", + "node-sass": "^4.11.0", "nodemon": "^1.18.9", "pixelmatch": "^4.0.2", "postcss": "^7.0.14", "prettier": "1.16.4", "stylelint": "^9.10.1", "stylelint-config-recommended": "^2.1.0", - "stylelint-scss": "^3.5.3", + "stylelint-scss": "^3.5.4", "vue-jest": "^4.0.0-beta.2", "webpack-dev-server": "^3.1.14", "yarn-deduplicate": "^1.1.1" diff --git a/qa/Rakefile b/qa/Rakefile index d0101740f1a..7ac018f7286 100644 --- a/qa/Rakefile +++ b/qa/Rakefile @@ -27,9 +27,9 @@ task :run_artillery_load_tests do end urls = YAML.safe_load(File.read(urls_file)) - ENV['HOST_URL'] = urls[:host] - ENV['LARGE_ISSUE_URL'] = urls[:large_issue] - ENV['LARGE_MR_URL'] = urls[:large_mr] + ENV['HOST_URL'] = urls["host"] + ENV['LARGE_ISSUE_URL'] = urls["large_issue"] + ENV['LARGE_MR_URL'] = urls["large_mr"] end sh('artillery run load/artillery.yml -o report.json') diff --git a/qa/load/artillery.yml b/qa/load/artillery.yml index e2c3c293d8b..17d253ec480 100644 --- a/qa/load/artillery.yml +++ b/qa/load/artillery.yml @@ -1,15 +1,18 @@ config: target: "{{ $processEnvironment.HOST_URL }}" + http: + pool: 10 # All HTTP requests from all virtual users will be sent over the same <pool> connections. + # This also means that there is a limit on the number of requests sent per second. phases: - - duration: 60 - arrivalRate: 1 + - duration: 30 + arrivalRate: 10 name: "Warm up" - - duration: 120 - arrivalRate: 1 - rampTo: 50 + - duration: 90 + arrivalRate: 10 + rampTo: 100 name: "Gradual ramp up" - - duration: 60 - arrivalRate: 50 + - duration: 90 + arrivalRate: 100 name: "Sustained max load" scenarios: - name: "Visit large issue url" diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb index c06f13ee204..1eada4a6c28 100644 --- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb @@ -3,7 +3,29 @@ module QA context 'Create' do describe 'Merge request creation' do - it 'user creates a new merge request' do + it 'user creates a new merge request', :smoke do + Runtime::Browser.visit(:gitlab, Page::Main::Login) + Page::Main::Login.act { sign_in_using_credentials } + + current_project = Resource::Project.fabricate! do |project| + project.name = 'project-with-merge-request' + end + + merge_request_title = 'This is a merge request' + merge_request_description = 'Great feature' + + Resource::MergeRequest.fabricate! do |merge_request| + merge_request.title = merge_request_title + merge_request.description = merge_request_description + merge_request.project = current_project + end + + expect(page).to have_content(merge_request_title) + expect(page).to have_content(merge_request_description) + expect(page).to have_content(/Opened [\w\s]+ ago/) + end + + it 'user creates a new merge request with a milestone and label' do gitlab_account_username = "@#{Runtime::User.username}" Runtime::Browser.visit(:gitlab, Page::Main::Login) @@ -24,9 +46,12 @@ module QA label.description = 'Merge Request label' end + merge_request_title = 'This is a merge request with a milestone and a label' + merge_request_description = 'Great feature with milestone' + Resource::MergeRequest.fabricate! do |merge_request| - merge_request.title = 'This is a merge request with a milestone' - merge_request.description = 'Great feature with milestone' + merge_request.title = merge_request_title + merge_request.description = merge_request_description merge_request.project = current_project merge_request.milestone = current_milestone merge_request.assignee = 'me' @@ -34,8 +59,8 @@ module QA end Page::MergeRequest::Show.perform do |merge_request| - expect(merge_request).to have_content('This is a merge request with a milestone') - expect(merge_request).to have_content('Great feature with milestone') + expect(merge_request).to have_content(merge_request_title) + expect(merge_request).to have_content(merge_request_description) expect(merge_request).to have_content(/Opened [\w\s]+ ago/) expect(merge_request).to have_assignee(gitlab_account_username) expect(merge_request).to have_label(new_label.title) @@ -47,25 +72,4 @@ module QA end end end - - describe 'creates a merge request', :smoke do - it 'user creates a new merge request' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.act { sign_in_using_credentials } - - current_project = Resource::Project.fabricate! do |project| - project.name = 'project-with-merge-request' - end - - Resource::MergeRequest.fabricate! do |merge_request| - merge_request.title = 'This is a merge request' - merge_request.description = 'Great feature' - merge_request.project = current_project - end - - expect(page).to have_content('This is a merge request') - expect(page).to have_content('Great feature') - expect(page).to have_content(/Opened [\w\s]+ ago/) - end - end end diff --git a/qa/qa/tools/generate_perf_testdata.rb b/qa/qa/tools/generate_perf_testdata.rb index 0a0dbdf5b15..4fda49c8e48 100644 --- a/qa/qa/tools/generate_perf_testdata.rb +++ b/qa/qa/tools/generate_perf_testdata.rb @@ -46,7 +46,7 @@ module QA threads_arr.each(&:join) STDOUT.puts "\nURLs: #{@urls}" - File.open("urls.yml", "w") { |file| file.puts @urls.to_yaml } + File.open("urls.yml", "w") { |file| file.puts @urls.stringify_keys.to_yaml } STDOUT.puts "\nDone" end diff --git a/scripts/frontend/stylelint/stylelint-duplicate-selectors.js b/scripts/frontend/stylelint/stylelint-duplicate-selectors.js new file mode 100644 index 00000000000..4b46ee21a7a --- /dev/null +++ b/scripts/frontend/stylelint/stylelint-duplicate-selectors.js @@ -0,0 +1,23 @@ +const stylelint = require('stylelint'); +const utils = require('./stylelint-utils'); +const ruleName = 'stylelint-gitlab/duplicate-selectors'; + +const messages = stylelint.utils.ruleMessages(ruleName, { + expected: (selector1, selector2) => { + return `"${selector1}" and "${selector2}" have the same properties.`; + }, +}); + +module.exports = stylelint.createPlugin(ruleName, function(enabled) { + if (!enabled) { + return; + } + + return function(root, result) { + const selectorGroups = {}; + utils.createPropertiesHashmap(root, result, ruleName, messages, selectorGroups, true); + }; +}); + +module.exports.ruleName = ruleName; +module.exports.messages = messages; diff --git a/scripts/frontend/stylelint/stylelint-utility-classes.js b/scripts/frontend/stylelint/stylelint-utility-classes.js new file mode 100644 index 00000000000..8a1cfdbf302 --- /dev/null +++ b/scripts/frontend/stylelint/stylelint-utility-classes.js @@ -0,0 +1,24 @@ +const stylelint = require('stylelint'); +const utils = require('./stylelint-utils'); +const utilityClasses = require('./utility-classes-map.js'); + +const ruleName = 'stylelint-gitlab/utility-classes'; + +const messages = stylelint.utils.ruleMessages(ruleName, { + expected: (selector1, selector2) => { + return `"${selector1}" has the same properties as our BS4 utility class "${selector2}" so please use that instead.`; + }, +}); + +module.exports = stylelint.createPlugin(ruleName, function(enabled) { + if (!enabled) { + return; + } + + return function(root, result) { + utils.createPropertiesHashmap(root, result, ruleName, messages, utilityClasses, false); + }; +}); + +module.exports.ruleName = ruleName; +module.exports.messages = messages; diff --git a/scripts/frontend/stylelint/stylelint-utility-map.js b/scripts/frontend/stylelint/stylelint-utility-map.js new file mode 100644 index 00000000000..7e012b157b3 --- /dev/null +++ b/scripts/frontend/stylelint/stylelint-utility-map.js @@ -0,0 +1,54 @@ +const sass = require('node-sass'); +const postcss = require('postcss'); +const fs = require('fs'); +const path = require('path'); +const prettier = require('prettier'); + +const utils = require('./stylelint-utils'); +const ROOT_PATH = path.resolve(__dirname, '../../..'); +const hashMapPath = path.resolve(__dirname, './utility-classes-map.js'); + +// +// This creates a JS based hash map (saved in utility-classes-map.js) of the different values in the utility classes +// +sass.render( + { + data: ` + @import './functions'; + @import './variables'; + @import './mixins'; + @import './utilities'; + `, + includePaths: [path.resolve(ROOT_PATH, 'node_modules/bootstrap/scss')], + }, + (err, result) => { + if (err) console.error('Error ', err); + + const cssResult = result.css.toString(); + + // We just use postcss to create a CSS tree + postcss([]) + .process(cssResult, { + // This supresses a postcss warning + from: undefined, + }) + .then(result => { + const selectorGroups = {}; + utils.createPropertiesHashmap(result.root, result, null, null, selectorGroups, true); + + const prettierOptions = prettier.resolveConfig.sync(hashMapPath); + const prettyHashmap = prettier.format( + `module.exports = ${JSON.stringify(selectorGroups)};`, + prettierOptions, + ); + + fs.writeFile(hashMapPath, prettyHashmap, function(err) { + if (err) { + return console.log(err); + } + + console.log('The file was saved!'); + }); + }); + }, +); diff --git a/scripts/frontend/stylelint/stylelint-utils.js b/scripts/frontend/stylelint/stylelint-utils.js new file mode 100644 index 00000000000..2d931c1c4c2 --- /dev/null +++ b/scripts/frontend/stylelint/stylelint-utils.js @@ -0,0 +1,77 @@ +const stylelint = require('stylelint'); +const md5 = require('md5'); + +module.exports.createPropertiesHashmap = ( + ruleRoot, + result, + ruleName, + messages, + selectorGroups, + addSelectors, +) => { + ruleRoot.walkRules(rule => { + const selector = rule.selector.replace(/(?:\r\n|\r|\n)/g, ' '); + + if ( + rule && + rule.parent && + rule.parent.type != 'atrule' && + !( + selector.includes('-webkit-') || + selector.includes('-moz-') || + selector.includes('-o-') || + selector.includes('-ms-') || + selector.includes(':') + ) + ) { + let cssArray = []; + rule.nodes.forEach(function(property) { + const { prop, value } = property; + if (property && value) { + const propval = `${prop}${value}${property.important ? '!important' : ''}`; + cssArray.push(propval); + } + }); + + cssArray = cssArray.sort(); + const cssContent = cssArray.toString(); + + if (cssContent) { + const hashValue = md5(cssContent); + const selObj = selectorGroups[hashValue]; + + const selectorLine = `${selector} (${ + rule.source.input.file ? rule.source.input.file + ' -' : '' + }${rule.source.start.line}:${rule.source.start.column})`; + + if (selObj) { + if (selectorGroups[hashValue].selectors.indexOf(selector) == -1) { + let lastSelector = + selectorGroups[hashValue].selectors[selectorGroups[hashValue].selectors.length - 1]; + + // So we have nicer formatting if it is the same file, we remove the filename + lastSelector = lastSelector.replace(`${rule.source.input.file} - `, ''); + + if (messages) { + stylelint.utils.report({ + result, + ruleName, + message: messages.expected(selector, lastSelector), + node: rule, + word: rule.node, + }); + } + + if (addSelectors) { + selectorGroups[hashValue].selectors.push(selectorLine); + } + } + } else if (addSelectors) { + selectorGroups[hashValue] = { + selectors: [selectorLine], + }; + } + } + } + }); +}; diff --git a/scripts/frontend/stylelint/utility-classes-map.js b/scripts/frontend/stylelint/utility-classes-map.js new file mode 100644 index 00000000000..1929f950f6c --- /dev/null +++ b/scripts/frontend/stylelint/utility-classes-map.js @@ -0,0 +1,216 @@ +module.exports = { + '99097f29a9473b56eacdb9ff0681c366': { selectors: ['.align-baseline (1:1)'] }, + d969b318bb994e104e8c965006d71cb7: { selectors: ['.align-top (4:1)'] }, + '8cd54ab97b9cc43cb9d13d2ea7c601c7': { selectors: ['.align-middle (7:1)'] }, + dd06eb6c49e979b7a9fdaa7119aa0a0b: { selectors: ['.align-bottom (10:1)'] }, + '0af1e90cbc468615e299ec9f49e97c4a': { selectors: ['.align-text-bottom (13:1)'] }, + '50af706df238cf59bdc634fc684ba0c9': { selectors: ['.align-text-top (16:1)'] }, + c968922e6e47445362129a684b5913c0: { selectors: ['.bg-primary (19:1)'] }, + '3c397f9786c24cff4779a11cf5b3d7e7': { selectors: ['.bg-secondary (27:1)'] }, + '659677469a4477267fabc1788f7cad4e': { selectors: ['.bg-success (35:1)'] }, + '56d246d5b6a708a4c6f78dbd2444106c': { selectors: ['.bg-info (43:1)'] }, + '6bec0a33df3a6380c30103db5c273455': { selectors: ['.bg-warning (51:1)'] }, + '0ce5d074c8667ce6c32360658f428d5d': { selectors: ['.bg-danger (59:1)'] }, + '0d0269c62a01e97caa9039d227a25d12': { selectors: ['.bg-light (67:1)'] }, + '3a56309ad8c5b46ebcc3b13fe1987ac1': { selectors: ['.bg-dark (75:1)'] }, + '0e252f8dd392a33343d3d5efc1e3194a': { selectors: ['.bg-white (83:1)'] }, + '3af6f52f0ed4f98e797d5f10a35ca6bc': { selectors: ['.bg-transparent (86:1)'] }, + '16da7fdce74577ceab356509db565612': { selectors: ['.border (89:1)'] }, + '929622517ca05efde3b51e5f1a57064e': { selectors: ['.border-top (92:1)'] }, + '7283090353df54f1d515a6ceddfb9693': { selectors: ['.border-right (95:1)'] }, + bd5670d71332c652b46db82949042e31: { selectors: ['.border-bottom (98:1)'] }, + fa71e003d04734a898a85cc5285e3cbb: { selectors: ['.border-left (101:1)'] }, + ed482cea071e316f29d78fd93c3f3644: { selectors: ['.border-0 (104:1)'] }, + '90cb661baf21e10be6e479cb0544b1a7': { selectors: ['.border-top-0 (107:1)'] }, + '8a32707eaa09fc998bf8cc915710b60c': { selectors: ['.border-right-0 (110:1)'] }, + a6f01957e142a000e7742b31ac6c2331: { selectors: ['.border-bottom-0 (113:1)'] }, + c740fe952cc1985ee14f7d1c7a359a29: { selectors: ['.border-left-0 (116:1)'] }, + af9dd93e9780306ffa4bb25a6384902f: { selectors: ['.border-primary (119:1)'] }, + afa290dfe58cca06be5924ceae1b019b: { selectors: ['.border-secondary (122:1)'] }, + '9b1ac460bdddf1e0164d7bf988cc2da8': { selectors: ['.border-success (125:1)'] }, + '091cbf41d6be12061382fa571ee1ce82': { selectors: ['.border-info (128:1)'] }, + '3ada321d4a387901dad6d80e1b6be3fd': { selectors: ['.border-warning (131:1)'] }, + '13b4713dd52c1e359d1b43dd658cb249': { selectors: ['.border-danger (134:1)'] }, + '0048e110875ea22b04104d55e764a367': { selectors: ['.border-light (137:1)'] }, + a900b6b567c9a911326cdd0e19f40f8e: { selectors: ['.border-dark (140:1)'] }, + '78bcd867ac9677c743c2bc33b872f27b': { selectors: ['.border-white (143:1)'] }, + e0fc10c49c7b7f4d1924336d21a4f64e: { selectors: ['.rounded (146:1)'] }, + '1b74b9d0a7d6a59281b5b5cae43c859a': { selectors: ['.rounded-top (149:1)'] }, + '20b75f55f39e662e038d51a6442c03df': { selectors: ['.rounded-right (153:1)'] }, + '83ea6db794873239c21f44af25618677': { selectors: ['.rounded-bottom (157:1)'] }, + '8464e9e8001e65dfc06397436a5eebd7': { selectors: ['.rounded-left (161:1)'] }, + '59c2f788287fa43caf5891adfc5c796e': { selectors: ['.rounded-circle (165:1)'] }, + '31a632ba94f8c41558bd6044458f1459': { selectors: ['.rounded-0 (168:1)'] }, + '16aaf53ab29d6b248b0257f2fa413914': { selectors: ['.d-none (176:1)'] }, + '4f42736ac9217039ed791b4306e60aeb': { selectors: ['.d-inline (179:1)'] }, + '067efa04b76649e8afcdceb9f5f7e870': { selectors: ['.d-inline-block (182:1)'] }, + de54f49149fb9b512aa79ad9ada838f2: { selectors: ['.d-block (185:1)'] }, + '80fc32acbc0c28ee890a160c23529d26': { selectors: ['.d-table (188:1)'] }, + '6a87b1db48298ca94cbe5dee79a6eed1': { selectors: ['.d-table-row (191:1)'] }, + b9896f0d94760bf5920f47904e9f7512: { selectors: ['.d-table-cell (194:1)'] }, + d25c51f38c4d057209b96c664de68c44: { selectors: ['.d-flex (197:1)'] }, + e72d46b636d5b8e17e771daa95793f33: { selectors: ['.d-inline-flex (200:1)'] }, + '2c433b7c14a5ae32cfa8ec7867ee8526': { selectors: ['.embed-responsive (303:1)'] }, + '56b318b8d8eb845b769d60cefcd131bb': { + selectors: [ + '.embed-responsive .embed-responsive-item, .embed-responsive iframe, .embed-responsive embed, .embed-responsive object, .embed-responsive video (312:3)', + ], + }, + c5009af89633c4d2f71a0a9fa333630d: { selectors: ['.flex-row (337:1)'] }, + '7b06a3d956579cd64b6f5b1a57255369': { selectors: ['.flex-column (340:1)'] }, + '21744a8c4dc6ed1519903b4236b00af4': { selectors: ['.flex-row-reverse (343:1)'] }, + '18d903735f9c71070b6d8166aa1112f1': { selectors: ['.flex-column-reverse (346:1)'] }, + e2a57aa8196347d4da84f33a4f551325: { selectors: ['.flex-wrap (349:1)'] }, + b6b29f75b174b5609f9e7d5eef457b70: { selectors: ['.flex-nowrap (352:1)'] }, + '839230fc7c0abacb6418b49d8f10b27f': { selectors: ['.flex-wrap-reverse (355:1)'] }, + '924d9b261944a8e8ff684d5b519062bb': { selectors: ['.flex-fill (358:1)'] }, + '5ed396aeb08464b7df8fc37d29455319': { selectors: ['.flex-grow-0 (361:1)'] }, + '94251dc4d012339a3e37df6196fc79bb': { selectors: ['.flex-grow-1 (364:1)'] }, + '0eeed7dabca0452a46574776a4485e6e': { selectors: ['.flex-shrink-0 (367:1)'] }, + c69e60d5e51a1b74d22b172ab98ef9d5: { selectors: ['.flex-shrink-1 (370:1)'] }, + '03401c1a81eb6d4639f020f76dd60176': { selectors: ['.justify-content-start (373:1)'] }, + '39e3d2c344e78869c98ef099249e717d': { selectors: ['.justify-content-end (376:1)'] }, + '3b2d00c0bea857ab78a71b0872842980': { selectors: ['.justify-content-center (379:1)'] }, + b1c3c9edd20ed7c08b43863d38ebee40: { selectors: ['.justify-content-between (382:1)'] }, + a11b4b1d983c5fa75777f273e998f73e: { selectors: ['.justify-content-around (385:1)'] }, + '50e33f29f65bfffa6a3591fcb6045ca9': { selectors: ['.align-items-start (388:1)'] }, + e44b276e47415ec19b74cc16740ada1d: { selectors: ['.align-items-end (391:1)'] }, + '4a9d2716bca651758564059dceed1271': { selectors: ['.align-items-center (394:1)'] }, + fd970b017f7f558f30cb273bf71ede7d: { selectors: ['.align-items-baseline (397:1)'] }, + '7204b6b00b69f8af1e4a24c9b6e7f7f9': { selectors: ['.align-items-stretch (400:1)'] }, + '350fbb74eb70bd05f9438067c3990e9f': { selectors: ['.align-content-start (403:1)'] }, + '74d61397b4fcbf608f3dba39ab3b2a1b': { selectors: ['.align-content-end (406:1)'] }, + eed1ab4ee9e5b327a434512176741548: { selectors: ['.align-content-center (409:1)'] }, + '19878ab832978ef7e1746ac2fe4084b2': { selectors: ['.align-content-between (412:1)'] }, + dded333d0522692809517039f5a727c1: { selectors: ['.align-content-around (415:1)'] }, + '5cbb83ea2af7e9db8ef13f4c7d6db875': { selectors: ['.align-content-stretch (418:1)'] }, + dc3df46d3c023184d375a63a71916646: { selectors: ['.align-self-auto (421:1)'] }, + '0c6d2d8c9732c571f9cf61a4b1d2877f': { selectors: ['.align-self-start (424:1)'] }, + fe7c6071e3e17214df1bdd38850d9ff0: { selectors: ['.align-self-end (427:1)'] }, + '9611bbad74d72d50cf238088576a5089': { selectors: ['.align-self-center (430:1)'] }, + '4bc5edddf5981866946175bfedb7247f': { selectors: ['.align-self-baseline (433:1)'] }, + '4fffdd27ec60120ec9ed16fd7feef801': { selectors: ['.align-self-stretch (436:1)'] }, + '39e658501f5502b35919f02fa9591360': { selectors: ['.float-left (719:1)'] }, + b51436c537ffc4269b1533e44d7c3467: { selectors: ['.float-right (722:1)'] }, + c4597a87d2c793a6d696cfe06f6c95ce: { selectors: ['.float-none (725:1)'] }, + aaf8dc6e0768e59f3098a98a5c144d66: { selectors: ['.position-static (760:1)'] }, + '79592de2383045d15ab57d35aa1dab95': { selectors: ['.position-relative (763:1)'] }, + a7c272f53d0368730bde4c2740ffb5c3: { selectors: ['.position-absolute (766:1)'] }, + dad0bb92d53f17cf8affc10f77824b7f: { selectors: ['.position-fixed (769:1)'] }, + '6da0f6a7354a75fe6c95b08a4cabc06f': { selectors: ['.position-sticky (772:1)'] }, + '66602e21eea7b673883155c8f42b9590': { selectors: ['.fixed-top (775:1)'] }, + '33ea70eb6db7f6ab3469680f182abb19': { selectors: ['.fixed-bottom (782:1)'] }, + '405e9dd7c9919943af14658313fd31e4': { selectors: ['.sr-only (795:1)'] }, + '9220ad156a70c2586b15fe2b9b6108b2': { selectors: ['.shadow-sm (813:1)'] }, + b1b8c0ff70767ca2160811a026766982: { selectors: ['.shadow (816:1)'] }, + da0792abe99964acb6692a03c61d6dd8: { selectors: ['.shadow-lg (819:1)'] }, + bb2173057af1cf20e687469b2d9cbb3c: { selectors: ['.shadow-none (822:1)'] }, + '6d8abb6519a186483b25429ab8b9765e': { selectors: ['.w-25 (825:1)'] }, + a087c1ffdf8ead76cdd37445b414d63e: { selectors: ['.w-50 (828:1)'] }, + '28180742013a90275be5633e6ec0dd51': { selectors: ['.w-75 (831:1)'] }, + '195a03bc95a0af0ba6c8824db97a0b2f': { selectors: ['.w-100 (834:1)'] }, + e67c74b650d6236b03be9dfc10c78e32: { selectors: ['.w-auto (837:1)'] }, + c1b6262b3ee069addc1fbe46f64aac4e: { selectors: ['.h-25 (840:1)'] }, + a520396ae349bef86145e0761aa0699e: { selectors: ['.h-50 (843:1)'] }, + '7c53b57d54beb087fd7ab8b669c5fe60': { selectors: ['.h-75 (846:1)'] }, + ad74f1972cb745b7a78b03e16a387f21: { selectors: ['.h-100 (849:1)'] }, + '2cd49c3d63d260ba4f0b23c559ad05e0': { selectors: ['.h-auto (852:1)'] }, + '0b43071a67efc45ee1735fdc2491313c': { selectors: ['.mw-100 (855:1)'] }, + eac31a6f08e5c935e24b97df0fdad579: { selectors: ['.mh-100 (858:1)'] }, + cfdb4f497b16074959bfd3deb7ea9c42: { selectors: ['.m-0 (861:1)'] }, + '4d666c270ba50524312d97c4b937d153': { selectors: ['.mt-0, .my-0 (864:1)'] }, + eccf47ccd76ceffb4b139cb6c080b5ac: { selectors: ['.mr-0, .mx-0 (868:1)'] }, + '9bc513e73c0bdc6efdf170cb31de16d1': { selectors: ['.mb-0, .my-0 (872:1)'] }, + e99cfc55b03f0e67f11628b19889ad7b: { selectors: ['.ml-0, .mx-0 (876:1)'] }, + e1c39484d90d2acaa00973531f47f738: { selectors: ['.m-1 (880:1)'] }, + '63791bc02eccfdfa2c01621a801e565f': { selectors: ['.mt-1, .my-1 (883:1)'] }, + bcb27ab9d7dcfdd0d7cacad02709966c: { selectors: ['.mr-1, .mx-1 (887:1)'] }, + cb5d1c4328e25b5bc93be9a252973690: { selectors: ['.mb-1, .my-1 (891:1)'] }, + b80b1010c7dcfbb30bed9015c4f2e969: { selectors: ['.ml-1, .mx-1 (895:1)'] }, + ecab1c9cdf8a562e3c0f70307aeafa89: { selectors: ['.m-2 (899:1)'] }, + '6505fe17fbbd88b1884113a754aa82ab': { selectors: ['.mt-2, .my-2 (902:1)'] }, + '6f0c7d09d1e729f332c4671ccc2b48c0': { selectors: ['.mr-2, .mx-2 (906:1)'] }, + '70ef7b668b382b3c747b2d73e08cdbed': { selectors: ['.mb-2, .my-2 (910:1)'] }, + '2d7f277cc78ed324a8fc1f71ab281e1f': { selectors: ['.ml-2, .mx-2 (914:1)'] }, + '8ebcfe52fd4024861082ffb1735747a7': { selectors: ['.m-3 (918:1)'] }, + '9965fb516bdb72b87023a533123a8035': { selectors: ['.mt-3, .my-3 (921:1)'] }, + b1fcbbb1dc6226f6da6000830088e051: { selectors: ['.mr-3, .mx-3 (925:1)'] }, + '02204826cfbe3da98535c0d802870940': { selectors: ['.mb-3, .my-3 (929:1)'] }, + '0259859060250ae6b730218733e7a437': { selectors: ['.ml-3, .mx-3 (933:1)'] }, + '8cf300dab2a4994a105eeddda826f2e6': { selectors: ['.m-4 (937:1)'] }, + '1ba62fdddd3349f52a452050688905c7': { selectors: ['.mt-4, .my-4 (940:1)'] }, + '66a104129fa13db5a0829567fba6ee41': { selectors: ['.mr-4, .mx-4 (944:1)'] }, + eefcc4c10b79e70e8e8a5a66fb2b7aa1: { selectors: ['.mb-4, .my-4 (948:1)'] }, + eb1503656dc920d15a31116956fdffa4: { selectors: ['.ml-4, .mx-4 (952:1)'] }, + '79cbb6e5c9b73fd0be29d4fc5733a099': { selectors: ['.m-5 (956:1)'] }, + '67d8671699df706a428e7da42a7141cb': { selectors: ['.mt-5, .my-5 (959:1)'] }, + e9cb4a0a8a60ff018c87a0b7efa9de29: { selectors: ['.mr-5, .mx-5 (963:1)'] }, + '93f579214354dbd8cb60209c068f0086': { selectors: ['.mb-5, .my-5 (967:1)'] }, + '2a789d4af97d2b87fd0bf2b4626120cd': { selectors: ['.ml-5, .mx-5 (971:1)'] }, + '64a89d28e8287c1a0ac153001082644c': { selectors: ['.p-0 (975:1)'] }, + b03aa6db5ddf110bbdbefbbec43fda30: { selectors: ['.pt-0, .py-0 (978:1)'] }, + e38192ca32a98888d4c4876880f4fece: { selectors: ['.pr-0, .px-0 (982:1)'] }, + '70fe8ef50e999ddd29506f672c107069': { selectors: ['.pb-0, .py-0 (986:1)'] }, + '9355e8cd9109049726475ba356661bcf': { selectors: ['.pl-0, .px-0 (990:1)'] }, + '0d4c53468c2658c5324b9ec7a8ca6de2': { selectors: ['.p-1 (994:1)'] }, + d74e430b2a56b3a4e20065c972b7fa3f: { selectors: ['.pt-1, .py-1 (997:1)'] }, + '21e4644967aedd19888b6f4a700b629b': { selectors: ['.pr-1, .px-1 (1001:1)'] }, + e315a7b9b7a1d0df3ea7d95af5203a0b: { selectors: ['.pb-1, .py-1 (1005:1)'] }, + '14630ca122e1d9830a9ef5591c4097d0': { selectors: ['.pl-1, .px-1 (1009:1)'] }, + '5b1c65e5139e86e5f4755824f8b77d13': { selectors: ['.p-2 (1013:1)'] }, + '244af70950a1e200d3849f75ce51d707': { selectors: ['.pt-2, .py-2 (1016:1)'] }, + b583832738cad724c7c23e5c14ac9bfb: { selectors: ['.pr-2, .px-2 (1020:1)'] }, + e1e633c4f1375e8276154192d8899e39: { selectors: ['.pb-2, .py-2 (1024:1)'] }, + '676b01e25f0dbb3f7d2f2529231cda08': { selectors: ['.pl-2, .px-2 (1028:1)'] }, + '9b5165e3333b22801f2287f7983d7516': { selectors: ['.p-3 (1032:1)'] }, + '5bcaa9df87a507f6cd14659ea176bdc5': { selectors: ['.pt-3, .py-3 (1035:1)'] }, + f706637180776c5589385599705a2409: { selectors: ['.pr-3, .px-3 (1039:1)'] }, + '41157cfbcf47990b383b5b0379386ab2': { selectors: ['.pb-3, .py-3 (1043:1)'] }, + cac1e7a204bb6a1f42707b684ad46238: { selectors: ['.pl-3, .px-3 (1047:1)'] }, + '43e0671cd41a4b7590284888b607a134': { selectors: ['.p-4 (1051:1)'] }, + '116b0f95ebde1ff8907e488413a88854': { selectors: ['.pt-4, .py-4 (1054:1)'] }, + ecb06765fe691d892df000eebbb23dcc: { selectors: ['.pr-4, .px-4 (1058:1)'] }, + '1331503a48d36025c861e660bc615048': { selectors: ['.pb-4, .py-4 (1062:1)'] }, + f8665f7e547e499abd7ac63813b274f5: { selectors: ['.pl-4, .px-4 (1066:1)'] }, + '4160a315459f1b5a98255863f42136fe': { selectors: ['.p-5 (1070:1)'] }, + f55a6b2de6a434ec7b4375f06f4fad75: { selectors: ['.pt-5, .py-5 (1073:1)'] }, + '19391dc45c8d7730a86d521c28f52c3f': { selectors: ['.pr-5, .px-5 (1077:1)'] }, + '15898bcb7ff74a60006f9931422b4ad3': { selectors: ['.pb-5, .py-5 (1081:1)'] }, + '6290bdc6355aed1e9b27379003aa4828': { selectors: ['.pl-5, .px-5 (1085:1)'] }, + e57ec4fe9e8ed36e38f1c50041fc9f47: { selectors: ['.m-auto (1089:1)'] }, + f10380665932186d1effe0674a74ba12: { selectors: ['.mt-auto, .my-auto (1092:1)'] }, + '2ce71a27023eb50a47c24a99399faa28': { selectors: ['.mr-auto, .mx-auto (1096:1)'] }, + '196c77d357d314678cd3a99cfacbea96': { selectors: ['.mb-auto, .my-auto (1100:1)'] }, + ca007ce268b463a6bf42145cf5ce3685: { selectors: ['.ml-auto, .mx-auto (1104:1)'] }, + cb431b84034f2e710509c7656b3c6f16: { selectors: ['.text-monospace (1844:1)'] }, + a8fc5ca823f51d72673577064387a029: { selectors: ['.text-justify (1847:1)'] }, + '0bb94dfab7ca2c9892ebbd993b2baf0f': { selectors: ['.text-nowrap (1850:1)'] }, + aea4958ce85ddc0cbffca1015c3a7eba: { selectors: ['.text-truncate (1853:1)'] }, + '52b9443947b6b94a5c7e1b837da115e2': { selectors: ['.text-left (1858:1)'] }, + baaf5136fc6e1c54ba29b6040f166d5f: { selectors: ['.text-right (1861:1)'] }, + '282aa4319bee75af06cc2632b7124e26': { selectors: ['.text-center (1864:1)'] }, + '1cb1c8ad9b560eca25ebcefe95c1b7fa': { selectors: ['.text-lowercase (1899:1)'] }, + '45234533eac658ba2857e9c4d3bc78a5': { selectors: ['.text-uppercase (1902:1)'] }, + f9e3f64237f2e81b6aed84223a0ceb1d: { selectors: ['.text-capitalize (1905:1)'] }, + '09caca3d36aa9f3ef815e0da7e1a16b4': { selectors: ['.font-weight-light (1908:1)'] }, + '25189f4fad18eaeef19e349c6680834c': { selectors: ['.font-weight-normal (1911:1)'] }, + b2a9507678ec557603eb8ec077f0eb1f: { selectors: ['.font-weight-bold (1914:1)'] }, + '7d2da06b621a98a8599e5ec82e39eac8': { selectors: ['.font-italic (1917:1)'] }, + '0020d10e4fce033b418aace7c3143b82': { selectors: ['.text-white (1920:1)'] }, + '34ad81e372a038e6f78ae4f22bd4813d': { selectors: ['.text-primary (1923:1)'] }, + '9fde9a179d24755438ace2a874dda817': { + selectors: ['.text-secondary (1929:1)', '.text-muted (1974:1)'], + }, + '9ffcb1532b3fb397c0e818850683da29': { selectors: ['.text-success (1935:1)'] }, + f28fd089809bcd15d5684b158a0af98d: { selectors: ['.text-info (1941:1)'] }, + '6cac1cb5ee5149e91e45d15d0bdae310': { selectors: ['.text-warning (1947:1)'] }, + '2faab1e0abf22b20fdf05b9b01fff29b': { selectors: ['.text-danger (1953:1)'] }, + '46b52fea531aaaf29b63c40be2356849': { selectors: ['.text-light (1959:1)'] }, + '78f31d1ab6529decf28e0366a8ee81aa': { selectors: ['.text-dark (1965:1)'] }, + '45330b41b77e8880ad7680c51e0f61c4': { selectors: ['.text-body (1971:1)'] }, + '60d93588f62b5e85eb4f11dfd3461897': { selectors: ['.text-black-50 (1977:1)'] }, + '7dea35658553032ff7b7cc0287613b7c': { selectors: ['.text-white-50 (1980:1)'] }, + '61bf92980cac3d51d0cf1ba24c948fa1': { selectors: ['.text-hide (1983:1)'] }, + '7dcad258820769677bc60871fafe9b93': { selectors: ['.visible (1990:1)'] }, + '0f8833af4e2f4a6fc785bd7edc1e75b3': { selectors: ['.invisible (1993:1)'] }, +}; diff --git a/spec/factories/clusters/providers/gcp.rb b/spec/factories/clusters/providers/gcp.rb index a002ab28519..186c7c8027c 100644 --- a/spec/factories/clusters/providers/gcp.rb +++ b/spec/factories/clusters/providers/gcp.rb @@ -28,5 +28,9 @@ FactoryBot.define do gcp.make_errored('Something wrong') end end + + trait :abac_enabled do + legacy_abac true + end end end diff --git a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb index 8c2599615cb..2f7d359575e 100644 --- a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb +++ b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb @@ -5,9 +5,7 @@ describe 'Merge request > User scrolls to note on load', :js do let(:user) { project.creator } let(:merge_request) { create(:merge_request, source_project: project, author: user) } let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } - let(:resolved_note) { create(:diff_note_on_merge_request, :resolved, noteable: merge_request, project: project) } let(:fragment_id) { "#note_#{note.id}" } - let(:collapsed_fragment_id) { "#note_#{resolved_note.id}" } before do sign_in(user) @@ -45,13 +43,35 @@ describe 'Merge request > User scrolls to note on load', :js do end end - # TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034 - xit 'expands collapsed notes' do - visit "#{project_merge_request_path(project, merge_request)}#{collapsed_fragment_id}" - note_element = find(collapsed_fragment_id) - note_container = note_element.ancestor('.timeline-content') + context 'resolved notes' do + let(:collapsed_fragment_id) { "#note_#{resolved_note.id}" } - expect(note_element.visible?).to eq true - expect(note_container.find('.line_content.noteable_line.old', match: :first).visible?).to eq true + context 'when diff note' do + let(:resolved_note) { create(:diff_note_on_merge_request, :resolved, noteable: merge_request, project: project) } + + it 'expands collapsed notes' do + visit "#{project_merge_request_path(project, merge_request)}#{collapsed_fragment_id}" + + note_element = find(collapsed_fragment_id) + diff_container = note_element.ancestor('.diff-content') + + expect(note_element.visible?).to eq(true) + expect(diff_container.visible?).to eq(true) + end + end + + context 'when non-diff note' do + let(:non_diff_discussion) { create(:discussion_note_on_merge_request, :resolved, noteable: merge_request, project: project) } + let(:resolved_note) { create(:discussion_note_on_merge_request, :resolved, noteable: merge_request, project: project, in_reply_to: non_diff_discussion) } + + it 'expands collapsed replies' do + visit "#{project_merge_request_path(project, merge_request)}#{collapsed_fragment_id}" + + note_element = find(collapsed_fragment_id) + + expect(note_element.visible?).to eq(true) + expect(note_element.sibling('.replies-toggle')[:class]).to include('expanded') + end + end end end diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index 3090f1a2131..fe71cb7661a 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -319,7 +319,7 @@ describe 'Environment' do yield - GitPushService.new(project, user, params).execute + Git::BranchPushService.new(project, user, params).execute end end diff --git a/spec/javascripts/behaviors/secret_values_spec.js b/spec/frontend/behaviors/secret_values_spec.js index 5aaab093c0c..5aaab093c0c 100644 --- a/spec/javascripts/behaviors/secret_values_spec.js +++ b/spec/frontend/behaviors/secret_values_spec.js diff --git a/spec/javascripts/blob/blob_fork_suggestion_spec.js b/spec/frontend/blob/blob_fork_suggestion_spec.js index 9b81b7e6f92..9b81b7e6f92 100644 --- a/spec/javascripts/blob/blob_fork_suggestion_spec.js +++ b/spec/frontend/blob/blob_fork_suggestion_spec.js diff --git a/spec/javascripts/boards/modal_store_spec.js b/spec/frontend/boards/modal_store_spec.js index 3257a3fb8a3..3257a3fb8a3 100644 --- a/spec/javascripts/boards/modal_store_spec.js +++ b/spec/frontend/boards/modal_store_spec.js diff --git a/spec/javascripts/cycle_analytics/limit_warning_component_spec.js b/spec/frontend/cycle_analytics/limit_warning_component_spec.js index 13e9fe00a00..13e9fe00a00 100644 --- a/spec/javascripts/cycle_analytics/limit_warning_component_spec.js +++ b/spec/frontend/cycle_analytics/limit_warning_component_spec.js diff --git a/spec/javascripts/diffs/components/diff_stats_spec.js b/spec/frontend/diffs/components/diff_stats_spec.js index 984b3026209..984b3026209 100644 --- a/spec/javascripts/diffs/components/diff_stats_spec.js +++ b/spec/frontend/diffs/components/diff_stats_spec.js diff --git a/spec/javascripts/diffs/components/edit_button_spec.js b/spec/frontend/diffs/components/edit_button_spec.js index ccdae4cb312..ccdae4cb312 100644 --- a/spec/javascripts/diffs/components/edit_button_spec.js +++ b/spec/frontend/diffs/components/edit_button_spec.js diff --git a/spec/javascripts/diffs/components/hidden_files_warning_spec.js b/spec/frontend/diffs/components/hidden_files_warning_spec.js index 5bf5ddd27bd..5bf5ddd27bd 100644 --- a/spec/javascripts/diffs/components/hidden_files_warning_spec.js +++ b/spec/frontend/diffs/components/hidden_files_warning_spec.js diff --git a/spec/javascripts/diffs/components/no_changes_spec.js b/spec/frontend/diffs/components/no_changes_spec.js index e45d34bf9d5..e45d34bf9d5 100644 --- a/spec/javascripts/diffs/components/no_changes_spec.js +++ b/spec/frontend/diffs/components/no_changes_spec.js diff --git a/spec/javascripts/error_tracking/components/error_tracking_list_spec.js b/spec/frontend/error_tracking/components/error_tracking_list_spec.js index 503af3920a8..503af3920a8 100644 --- a/spec/javascripts/error_tracking/components/error_tracking_list_spec.js +++ b/spec/frontend/error_tracking/components/error_tracking_list_spec.js diff --git a/spec/javascripts/error_tracking/store/mutation_spec.js b/spec/frontend/error_tracking/store/mutation_spec.js index 8117104bdbc..8117104bdbc 100644 --- a/spec/javascripts/error_tracking/store/mutation_spec.js +++ b/spec/frontend/error_tracking/store/mutation_spec.js diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js b/spec/frontend/filtered_search/filtered_search_token_keys_spec.js index d1fea18dea8..d1fea18dea8 100644 --- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js +++ b/spec/frontend/filtered_search/filtered_search_token_keys_spec.js diff --git a/spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js b/spec/frontend/filtered_search/services/recent_searches_service_error_spec.js index ea7c146fa4f..ea7c146fa4f 100644 --- a/spec/javascripts/filtered_search/services/recent_searches_service_error_spec.js +++ b/spec/frontend/filtered_search/services/recent_searches_service_error_spec.js diff --git a/spec/javascripts/filtered_search/stores/recent_searches_store_spec.js b/spec/frontend/filtered_search/stores/recent_searches_store_spec.js index 56bb82ae941..56bb82ae941 100644 --- a/spec/javascripts/filtered_search/stores/recent_searches_store_spec.js +++ b/spec/frontend/filtered_search/stores/recent_searches_store_spec.js diff --git a/spec/javascripts/frequent_items/store/getters_spec.js b/spec/frontend/frequent_items/store/getters_spec.js index 1cd12eb6832..1cd12eb6832 100644 --- a/spec/javascripts/frequent_items/store/getters_spec.js +++ b/spec/frontend/frequent_items/store/getters_spec.js diff --git a/spec/frontend/helpers/vue_mount_component_helper.js b/spec/frontend/helpers/vue_mount_component_helper.js new file mode 100644 index 00000000000..6848c95d95d --- /dev/null +++ b/spec/frontend/helpers/vue_mount_component_helper.js @@ -0,0 +1,38 @@ +import Vue from 'vue'; + +const mountComponent = (Component, props = {}, el = null) => + new Component({ + propsData: props, + }).$mount(el); + +export const createComponentWithStore = (Component, store, propsData = {}) => + new Component({ + store, + propsData, + }); + +export const mountComponentWithStore = (Component, { el, props, store }) => + new Component({ + store, + propsData: props || {}, + }).$mount(el); + +export const mountComponentWithSlots = (Component, { props, slots }) => { + const component = new Component({ + propsData: props || {}, + }); + + component.$slots = slots; + + return component.$mount(); +}; + +/** + * Mount a component with the given render method. + * + * This helps with inserting slots that need to be compiled. + */ +export const mountComponentWithRender = (render, el = null) => + mountComponent(Vue.extend({ render }), {}, el); + +export default mountComponent; diff --git a/spec/javascripts/ide/lib/common/disposable_spec.js b/spec/frontend/ide/lib/common/disposable_spec.js index af12ca15369..af12ca15369 100644 --- a/spec/javascripts/ide/lib/common/disposable_spec.js +++ b/spec/frontend/ide/lib/common/disposable_spec.js diff --git a/spec/javascripts/ide/lib/diff/diff_spec.js b/spec/frontend/ide/lib/diff/diff_spec.js index 57f3ac3d365..57f3ac3d365 100644 --- a/spec/javascripts/ide/lib/diff/diff_spec.js +++ b/spec/frontend/ide/lib/diff/diff_spec.js diff --git a/spec/javascripts/ide/lib/editor_options_spec.js b/spec/frontend/ide/lib/editor_options_spec.js index d149a883166..d149a883166 100644 --- a/spec/javascripts/ide/lib/editor_options_spec.js +++ b/spec/frontend/ide/lib/editor_options_spec.js diff --git a/spec/javascripts/ide/lib/files_spec.js b/spec/frontend/ide/lib/files_spec.js index fe791aa2b74..fe791aa2b74 100644 --- a/spec/javascripts/ide/lib/files_spec.js +++ b/spec/frontend/ide/lib/files_spec.js diff --git a/spec/javascripts/ide/stores/modules/commit/mutations_spec.js b/spec/frontend/ide/stores/modules/commit/mutations_spec.js index 5de7a281d34..5de7a281d34 100644 --- a/spec/javascripts/ide/stores/modules/commit/mutations_spec.js +++ b/spec/frontend/ide/stores/modules/commit/mutations_spec.js diff --git a/spec/javascripts/ide/stores/modules/file_templates/getters_spec.js b/spec/frontend/ide/stores/modules/file_templates/getters_spec.js index 17cb457881f..17cb457881f 100644 --- a/spec/javascripts/ide/stores/modules/file_templates/getters_spec.js +++ b/spec/frontend/ide/stores/modules/file_templates/getters_spec.js diff --git a/spec/javascripts/ide/stores/modules/file_templates/mutations_spec.js b/spec/frontend/ide/stores/modules/file_templates/mutations_spec.js index 8e0e3ae99a1..8e0e3ae99a1 100644 --- a/spec/javascripts/ide/stores/modules/file_templates/mutations_spec.js +++ b/spec/frontend/ide/stores/modules/file_templates/mutations_spec.js diff --git a/spec/javascripts/ide/stores/modules/pane/getters_spec.js b/spec/frontend/ide/stores/modules/pane/getters_spec.js index 8a213323de0..8a213323de0 100644 --- a/spec/javascripts/ide/stores/modules/pane/getters_spec.js +++ b/spec/frontend/ide/stores/modules/pane/getters_spec.js diff --git a/spec/javascripts/ide/stores/modules/pane/mutations_spec.js b/spec/frontend/ide/stores/modules/pane/mutations_spec.js index b5fcd35912e..b5fcd35912e 100644 --- a/spec/javascripts/ide/stores/modules/pane/mutations_spec.js +++ b/spec/frontend/ide/stores/modules/pane/mutations_spec.js diff --git a/spec/javascripts/ide/stores/modules/pipelines/getters_spec.js b/spec/frontend/ide/stores/modules/pipelines/getters_spec.js index 4514896b5ea..4514896b5ea 100644 --- a/spec/javascripts/ide/stores/modules/pipelines/getters_spec.js +++ b/spec/frontend/ide/stores/modules/pipelines/getters_spec.js diff --git a/spec/javascripts/ide/stores/mutations/branch_spec.js b/spec/frontend/ide/stores/mutations/branch_spec.js index 29eb859ddaf..29eb859ddaf 100644 --- a/spec/javascripts/ide/stores/mutations/branch_spec.js +++ b/spec/frontend/ide/stores/mutations/branch_spec.js diff --git a/spec/javascripts/ide/stores/mutations/merge_request_spec.js b/spec/frontend/ide/stores/mutations/merge_request_spec.js index e30ca22022f..e30ca22022f 100644 --- a/spec/javascripts/ide/stores/mutations/merge_request_spec.js +++ b/spec/frontend/ide/stores/mutations/merge_request_spec.js diff --git a/spec/javascripts/image_diff/view_types_spec.js b/spec/frontend/image_diff/view_types_spec.js index e9639f46497..e9639f46497 100644 --- a/spec/javascripts/image_diff/view_types_spec.js +++ b/spec/frontend/image_diff/view_types_spec.js diff --git a/spec/javascripts/import_projects/store/getters_spec.js b/spec/frontend/import_projects/store/getters_spec.js index e5e4a95f473..e5e4a95f473 100644 --- a/spec/javascripts/import_projects/store/getters_spec.js +++ b/spec/frontend/import_projects/store/getters_spec.js diff --git a/spec/javascripts/import_projects/store/mutations_spec.js b/spec/frontend/import_projects/store/mutations_spec.js index 8db8e9819ba..8db8e9819ba 100644 --- a/spec/javascripts/import_projects/store/mutations_spec.js +++ b/spec/frontend/import_projects/store/mutations_spec.js diff --git a/spec/javascripts/jobs/components/empty_state_spec.js b/spec/frontend/jobs/components/empty_state_spec.js index a2df79bdda0..a2df79bdda0 100644 --- a/spec/javascripts/jobs/components/empty_state_spec.js +++ b/spec/frontend/jobs/components/empty_state_spec.js diff --git a/spec/javascripts/jobs/components/erased_block_spec.js b/spec/frontend/jobs/components/erased_block_spec.js index 8e0433d3fb7..8e0433d3fb7 100644 --- a/spec/javascripts/jobs/components/erased_block_spec.js +++ b/spec/frontend/jobs/components/erased_block_spec.js diff --git a/spec/javascripts/jobs/components/sidebar_detail_row_spec.js b/spec/frontend/jobs/components/sidebar_detail_row_spec.js index 42d11266dad..42d11266dad 100644 --- a/spec/javascripts/jobs/components/sidebar_detail_row_spec.js +++ b/spec/frontend/jobs/components/sidebar_detail_row_spec.js diff --git a/spec/javascripts/jobs/components/stuck_block_spec.js b/spec/frontend/jobs/components/stuck_block_spec.js index c320793b2be..c320793b2be 100644 --- a/spec/javascripts/jobs/components/stuck_block_spec.js +++ b/spec/frontend/jobs/components/stuck_block_spec.js diff --git a/spec/javascripts/jobs/store/getters_spec.js b/spec/frontend/jobs/store/getters_spec.js index 379114c3737..379114c3737 100644 --- a/spec/javascripts/jobs/store/getters_spec.js +++ b/spec/frontend/jobs/store/getters_spec.js diff --git a/spec/javascripts/jobs/store/mutations_spec.js b/spec/frontend/jobs/store/mutations_spec.js index d7908efcf13..d7908efcf13 100644 --- a/spec/javascripts/jobs/store/mutations_spec.js +++ b/spec/frontend/jobs/store/mutations_spec.js diff --git a/spec/javascripts/labels_select_spec.js b/spec/frontend/labels_select_spec.js index acfdc885032..acfdc885032 100644 --- a/spec/javascripts/labels_select_spec.js +++ b/spec/frontend/labels_select_spec.js diff --git a/spec/javascripts/lib/utils/cache_spec.js b/spec/frontend/lib/utils/cache_spec.js index 2fe02a7592c..2fe02a7592c 100644 --- a/spec/javascripts/lib/utils/cache_spec.js +++ b/spec/frontend/lib/utils/cache_spec.js diff --git a/spec/javascripts/lib/utils/grammar_spec.js b/spec/frontend/lib/utils/grammar_spec.js index 377b2ffb48c..377b2ffb48c 100644 --- a/spec/javascripts/lib/utils/grammar_spec.js +++ b/spec/frontend/lib/utils/grammar_spec.js diff --git a/spec/javascripts/lib/utils/image_utility_spec.js b/spec/frontend/lib/utils/image_utility_spec.js index a7eff419fba..a7eff419fba 100644 --- a/spec/javascripts/lib/utils/image_utility_spec.js +++ b/spec/frontend/lib/utils/image_utility_spec.js diff --git a/spec/javascripts/lib/utils/number_utility_spec.js b/spec/frontend/lib/utils/number_utility_spec.js index 818404bad81..818404bad81 100644 --- a/spec/javascripts/lib/utils/number_utility_spec.js +++ b/spec/frontend/lib/utils/number_utility_spec.js diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js index 0a266b19ea5..0a266b19ea5 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/frontend/lib/utils/text_utility_spec.js diff --git a/spec/javascripts/locale/ensure_single_line_spec.js b/spec/frontend/locale/ensure_single_line_spec.js index 20b04cab9c8..20b04cab9c8 100644 --- a/spec/javascripts/locale/ensure_single_line_spec.js +++ b/spec/frontend/locale/ensure_single_line_spec.js diff --git a/spec/javascripts/locale/sprintf_spec.js b/spec/frontend/locale/sprintf_spec.js index 52e903b819f..52e903b819f 100644 --- a/spec/javascripts/locale/sprintf_spec.js +++ b/spec/frontend/locale/sprintf_spec.js diff --git a/spec/frontend/mr_popover/__snapshots__/mr_popover_spec.js.snap b/spec/frontend/mr_popover/__snapshots__/mr_popover_spec.js.snap new file mode 100644 index 00000000000..5f9f13d591d --- /dev/null +++ b/spec/frontend/mr_popover/__snapshots__/mr_popover_spec.js.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MR Popover loaded state matches the snapshot 1`] = ` +<glpopover-stub + boundary="viewport" + placement="top" + show="" + target="" +> + <div + class="mr-popover" + > + <div + class="d-flex align-items-center justify-content-between" + > + <div + class="d-inline-flex align-items-center" + > + <div + class="issuable-status-box status-box status-box-open" + > + + Open + + </div> + + <span + class="text-secondary" + > + Opened + <time> + just now + </time> + </span> + </div> + + <ciicon-stub + cssclasses="" + size="16" + status="[object Object]" + /> + </div> + + <h5 + class="my-2" + > + MR Title + </h5> + + <div + class="text-secondary" + > + + foo/bar!1 + + </div> + </div> +</glpopover-stub> +`; + +exports[`MR Popover shows skeleton-loader while apollo is loading 1`] = ` +<glpopover-stub + boundary="viewport" + placement="top" + show="" + target="" +> + <div + class="mr-popover" + > + <div> + <glskeletonloading-stub + class="animation-container-small mt-1" + lines="1" + /> + </div> + + <h5 + class="my-2" + > + MR Title + </h5> + + <div + class="text-secondary" + > + + foo/bar!1 + + </div> + </div> +</glpopover-stub> +`; diff --git a/spec/frontend/mr_popover/mr_popover_spec.js b/spec/frontend/mr_popover/mr_popover_spec.js new file mode 100644 index 00000000000..79ed4163010 --- /dev/null +++ b/spec/frontend/mr_popover/mr_popover_spec.js @@ -0,0 +1,61 @@ +import MRPopover from '~/mr_popover/components/mr_popover'; +import { shallowMount } from '@vue/test-utils'; + +describe('MR Popover', () => { + let wrapper; + + beforeEach(() => { + wrapper = shallowMount(MRPopover, { + propsData: { + target: document.createElement('a'), + projectPath: 'foo/bar', + mergeRequestIID: '1', + mergeRequestTitle: 'MR Title', + }, + mocks: { + $apollo: { + loading: false, + }, + }, + }); + }); + + it('shows skeleton-loader while apollo is loading', () => { + wrapper.vm.$apollo.loading = true; + + expect(wrapper.element).toMatchSnapshot(); + }); + + describe('loaded state', () => { + it('matches the snapshot', () => { + wrapper.setData({ + mergeRequest: { + state: 'opened', + createdAt: new Date(), + headPipeline: { + detailedStatus: { + group: 'success', + status: 'status_success', + }, + }, + }, + }); + + expect(wrapper.element).toMatchSnapshot(); + }); + + it('does not show CI Icon if there is no pipeline data', () => { + wrapper.setData({ + mergeRequest: { + state: 'opened', + headPipeline: null, + stateHumanName: 'Open', + title: 'Merge Request Title', + createdAt: new Date(), + }, + }); + + expect(wrapper.contains('ciicon-stub')).toBe(false); + }); + }); +}); diff --git a/spec/javascripts/notebook/lib/highlight_spec.js b/spec/frontend/notebook/lib/highlight_spec.js index d71c5718858..d71c5718858 100644 --- a/spec/javascripts/notebook/lib/highlight_spec.js +++ b/spec/frontend/notebook/lib/highlight_spec.js diff --git a/spec/javascripts/notes/components/discussion_reply_placeholder_spec.js b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js index 07a366cf339..07a366cf339 100644 --- a/spec/javascripts/notes/components/discussion_reply_placeholder_spec.js +++ b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js diff --git a/spec/javascripts/notes/components/discussion_resolve_button_spec.js b/spec/frontend/notes/components/discussion_resolve_button_spec.js index 5024f40ec5d..5024f40ec5d 100644 --- a/spec/javascripts/notes/components/discussion_resolve_button_spec.js +++ b/spec/frontend/notes/components/discussion_resolve_button_spec.js diff --git a/spec/javascripts/notes/components/note_attachment_spec.js b/spec/frontend/notes/components/note_attachment_spec.js index b14a518b622..b14a518b622 100644 --- a/spec/javascripts/notes/components/note_attachment_spec.js +++ b/spec/frontend/notes/components/note_attachment_spec.js diff --git a/spec/javascripts/notes/components/note_edited_text_spec.js b/spec/frontend/notes/components/note_edited_text_spec.js index e4c8d954d50..e4c8d954d50 100644 --- a/spec/javascripts/notes/components/note_edited_text_spec.js +++ b/spec/frontend/notes/components/note_edited_text_spec.js diff --git a/spec/javascripts/performance_bar/services/performance_bar_service_spec.js b/spec/frontend/performance_bar/services/performance_bar_service_spec.js index cfec4b779e4..cfec4b779e4 100644 --- a/spec/javascripts/performance_bar/services/performance_bar_service_spec.js +++ b/spec/frontend/performance_bar/services/performance_bar_service_spec.js diff --git a/spec/javascripts/pipelines/blank_state_spec.js b/spec/frontend/pipelines/blank_state_spec.js index 033bd5ccb73..033bd5ccb73 100644 --- a/spec/javascripts/pipelines/blank_state_spec.js +++ b/spec/frontend/pipelines/blank_state_spec.js diff --git a/spec/javascripts/pipelines/empty_state_spec.js b/spec/frontend/pipelines/empty_state_spec.js index f12950b8fce..f12950b8fce 100644 --- a/spec/javascripts/pipelines/empty_state_spec.js +++ b/spec/frontend/pipelines/empty_state_spec.js diff --git a/spec/javascripts/pipelines/pipeline_store_spec.js b/spec/frontend/pipelines/pipeline_store_spec.js index 1d5754d1f05..1d5754d1f05 100644 --- a/spec/javascripts/pipelines/pipeline_store_spec.js +++ b/spec/frontend/pipelines/pipeline_store_spec.js diff --git a/spec/javascripts/pipelines/pipelines_store_spec.js b/spec/frontend/pipelines/pipelines_store_spec.js index ce21f788ed5..ce21f788ed5 100644 --- a/spec/javascripts/pipelines/pipelines_store_spec.js +++ b/spec/frontend/pipelines/pipelines_store_spec.js diff --git a/spec/javascripts/registry/getters_spec.js b/spec/frontend/registry/getters_spec.js index 839aa718997..839aa718997 100644 --- a/spec/javascripts/registry/getters_spec.js +++ b/spec/frontend/registry/getters_spec.js diff --git a/spec/javascripts/reports/components/report_link_spec.js b/spec/frontend/reports/components/report_link_spec.js index f879899e9c5..f879899e9c5 100644 --- a/spec/javascripts/reports/components/report_link_spec.js +++ b/spec/frontend/reports/components/report_link_spec.js diff --git a/spec/javascripts/reports/store/utils_spec.js b/spec/frontend/reports/store/utils_spec.js index 1679d120db2..1679d120db2 100644 --- a/spec/javascripts/reports/store/utils_spec.js +++ b/spec/frontend/reports/store/utils_spec.js diff --git a/spec/javascripts/sidebar/confidential_edit_buttons_spec.js b/spec/frontend/sidebar/confidential_edit_buttons_spec.js index 32da9f83112..32da9f83112 100644 --- a/spec/javascripts/sidebar/confidential_edit_buttons_spec.js +++ b/spec/frontend/sidebar/confidential_edit_buttons_spec.js diff --git a/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js b/spec/frontend/sidebar/confidential_edit_form_buttons_spec.js index 369088cb258..369088cb258 100644 --- a/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js +++ b/spec/frontend/sidebar/confidential_edit_form_buttons_spec.js diff --git a/spec/javascripts/sidebar/lock/edit_form_spec.js b/spec/frontend/sidebar/lock/edit_form_spec.js index ec10a999a40..ec10a999a40 100644 --- a/spec/javascripts/sidebar/lock/edit_form_spec.js +++ b/spec/frontend/sidebar/lock/edit_form_spec.js diff --git a/spec/javascripts/u2f/util_spec.js b/spec/frontend/u2f/util_spec.js index 32cd6891384..32cd6891384 100644 --- a/spec/javascripts/u2f/util_spec.js +++ b/spec/frontend/u2f/util_spec.js diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_container_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_container_spec.js index 16c8c939a6f..16c8c939a6f 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_container_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_container_spec.js diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_icon_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_icon_spec.js index f7c2376eebf..f7c2376eebf 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_icon_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_icon_spec.js diff --git a/spec/javascripts/vue_mr_widget/components/states/commit_edit_spec.js b/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js index 994d6255324..994d6255324 100644 --- a/spec/javascripts/vue_mr_widget/components/states/commit_edit_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/commit_edit_spec.js diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js index daf1cc2d98b..daf1cc2d98b 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_commit_message_dropdown_spec.js diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_commits_header_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js index 9ee2f88c78d..9ee2f88c78d 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_commits_header_spec.js +++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_commits_header_spec.js diff --git a/spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js b/spec/frontend/vue_mr_widget/stores/get_state_key_spec.js index b356ea85cad..b356ea85cad 100644 --- a/spec/javascripts/vue_mr_widget/stores/get_state_key_spec.js +++ b/spec/frontend/vue_mr_widget/stores/get_state_key_spec.js diff --git a/spec/javascripts/vue_shared/components/callout_spec.js b/spec/frontend/vue_shared/components/callout_spec.js index 91208dfb31a..91208dfb31a 100644 --- a/spec/javascripts/vue_shared/components/callout_spec.js +++ b/spec/frontend/vue_shared/components/callout_spec.js diff --git a/spec/javascripts/vue_shared/components/code_block_spec.js b/spec/frontend/vue_shared/components/code_block_spec.js index 6b91a20ff76..6b91a20ff76 100644 --- a/spec/javascripts/vue_shared/components/code_block_spec.js +++ b/spec/frontend/vue_shared/components/code_block_spec.js diff --git a/spec/javascripts/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js b/spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js index c4358f0d9cb..c4358f0d9cb 100644 --- a/spec/javascripts/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js +++ b/spec/frontend/vue_shared/components/diff_viewer/viewers/mode_changed_spec.js diff --git a/spec/javascripts/vue_shared/components/identicon_spec.js b/spec/frontend/vue_shared/components/identicon_spec.js index 0b3dbb61c96..0b3dbb61c96 100644 --- a/spec/javascripts/vue_shared/components/identicon_spec.js +++ b/spec/frontend/vue_shared/components/identicon_spec.js diff --git a/spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js b/spec/frontend/vue_shared/components/lib/utils/dom_utils_spec.js index 2388660b0c2..2388660b0c2 100644 --- a/spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js +++ b/spec/frontend/vue_shared/components/lib/utils/dom_utils_spec.js diff --git a/spec/javascripts/vue_shared/components/pagination_links_spec.js b/spec/frontend/vue_shared/components/pagination_links_spec.js index d0cb3731050..d0cb3731050 100644 --- a/spec/javascripts/vue_shared/components/pagination_links_spec.js +++ b/spec/frontend/vue_shared/components/pagination_links_spec.js diff --git a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js index 536bb57b946..536bb57b946 100644 --- a/spec/javascripts/vue_shared/components/time_ago_tooltip_spec.js +++ b/spec/frontend/vue_shared/components/time_ago_tooltip_spec.js diff --git a/spec/javascripts/vuex_shared/modules/modal/mutations_spec.js b/spec/frontend/vuex_shared/modules/modal/mutations_spec.js index d07f8ba1e65..d07f8ba1e65 100644 --- a/spec/javascripts/vuex_shared/modules/modal/mutations_spec.js +++ b/spec/frontend/vuex_shared/modules/modal/mutations_spec.js diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb new file mode 100644 index 00000000000..a21162adb42 --- /dev/null +++ b/spec/graphql/types/ci/detailed_status_type_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Types::Ci::DetailedStatusType do + it { expect(described_class.graphql_name).to eq('DetailedStatus') } + + it "has all fields" do + expect(described_class).to have_graphql_fields(:group, :icon, :favicon, + :details_path, :has_details, + :label, :text, :tooltip) + end +end diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb new file mode 100644 index 00000000000..4ea0f76fc28 --- /dev/null +++ b/spec/helpers/clusters_helper_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ClustersHelper do + describe '#has_rbac_enabled?' do + context 'when kubernetes platform has been created' do + let(:platform_kubernetes) { build_stubbed(:cluster_platform_kubernetes) } + let(:cluster) { build_stubbed(:cluster, :provided_by_gcp, platform_kubernetes: platform_kubernetes) } + + it 'returns kubernetes platform value' do + expect(helper.has_rbac_enabled?(cluster)).to be_truthy + end + end + + context 'when kubernetes platform has not been created yet' do + let(:cluster) { build_stubbed(:cluster, :providing_by_gcp) } + + it 'delegates to cluster provider' do + expect(helper.has_rbac_enabled?(cluster)).to be_truthy + end + + context 'when ABAC cluster is created' do + let(:provider) { build_stubbed(:cluster_provider_gcp, :abac_enabled) } + let(:cluster) { build_stubbed(:cluster, :providing_by_gcp, provider_gcp: provider) } + + it 'delegates to cluster provider' do + expect(helper.has_rbac_enabled?(cluster)).to be_falsy + end + end + end + end +end diff --git a/spec/javascripts/activities_spec.js b/spec/javascripts/activities_spec.js index 068b8eb65bc..23b6de7e4e0 100644 --- a/spec/javascripts/activities_spec.js +++ b/spec/javascripts/activities_spec.js @@ -7,7 +7,7 @@ import Pager from '~/pager'; describe('Activities', () => { window.gon || (window.gon = {}); - const fixtureTemplate = 'static/event_filter.html.raw'; + const fixtureTemplate = 'static/event_filter.html'; const filters = [ { id: 'all', diff --git a/spec/javascripts/ajax_loading_spinner_spec.js b/spec/javascripts/ajax_loading_spinner_spec.js index 9389fc94f17..89195a4397f 100644 --- a/spec/javascripts/ajax_loading_spinner_spec.js +++ b/spec/javascripts/ajax_loading_spinner_spec.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import AjaxLoadingSpinner from '~/ajax_loading_spinner'; describe('Ajax Loading Spinner', () => { - const fixtureTemplate = 'static/ajax_loading_spinner.html.raw'; + const fixtureTemplate = 'static/ajax_loading_spinner.html'; preloadFixtures(fixtureTemplate); beforeEach(() => { diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index e5b5707dcef..e10df1b45e7 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -24,13 +24,13 @@ const lazyAssert = function(done, assertFn) { describe('AwardsHandler', function() { const emojiData = getJSONFixture('emojis/emojis.json'); - preloadFixtures('snippets/show.html.raw'); + preloadFixtures('snippets/show.html'); beforeEach(function(done) { mock = new MockAdapter(axios); mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, emojiData); - loadFixtures('snippets/show.html.raw'); + loadFixtures('snippets/show.html'); loadAwardsHandler(true) .then(obj => { awardsHandler = obj; diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 681463aab66..7af8c984841 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -4,10 +4,10 @@ import '~/behaviors/quick_submit'; describe('Quick Submit behavior', function() { const keydownEvent = (options = { keyCode: 13, metaKey: true }) => $.Event('keydown', options); - preloadFixtures('snippets/show.html.raw'); + preloadFixtures('snippets/show.html'); beforeEach(() => { - loadFixtures('snippets/show.html.raw'); + loadFixtures('snippets/show.html'); $('form').submit(e => { // Prevent a form submit from moving us off the testing page e.preventDefault(); diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 1bde2bb3024..617fe49b059 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -3,10 +3,10 @@ import '~/behaviors/requires_input'; describe('requiresInput', () => { let submitButton; - preloadFixtures('branches/new_branch.html.raw'); + preloadFixtures('branches/new_branch.html'); beforeEach(() => { - loadFixtures('branches/new_branch.html.raw'); + loadFixtures('branches/new_branch.html'); submitButton = $('button[type="submit"]'); }); diff --git a/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js index 4843a0386b5..5e457a4e823 100644 --- a/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js +++ b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js @@ -9,7 +9,7 @@ import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; const FORM_SELECTOR = '.js-main-target-form .js-vue-comment-form'; describe('ShortcutsIssuable', function() { - const fixtureName = 'snippets/show.html.raw'; + const fixtureName = 'snippets/show.html'; preloadFixtures(fixtureName); beforeAll(done => { diff --git a/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js b/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js index 5f027f59fcf..68b4f261617 100644 --- a/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js +++ b/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js @@ -6,10 +6,10 @@ describe('Balsamiq integration spec', () => { let endpoint; let balsamiqViewer; - preloadFixtures('static/balsamiq_viewer.html.raw'); + preloadFixtures('static/balsamiq_viewer.html'); beforeEach(() => { - loadFixtures('static/balsamiq_viewer.html.raw'); + loadFixtures('static/balsamiq_viewer.html'); container = document.getElementById('js-balsamiq-viewer'); balsamiqViewer = new BalsamiqViewer(container); diff --git a/spec/javascripts/blob/blob_file_dropzone_spec.js b/spec/javascripts/blob/blob_file_dropzone_spec.js index 432d8a65b0a..cab06a0a9be 100644 --- a/spec/javascripts/blob/blob_file_dropzone_spec.js +++ b/spec/javascripts/blob/blob_file_dropzone_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import BlobFileDropzone from '~/blob/blob_file_dropzone'; describe('BlobFileDropzone', function() { - preloadFixtures('blob/show.html.raw'); + preloadFixtures('blob/show.html'); beforeEach(() => { - loadFixtures('blob/show.html.raw'); + loadFixtures('blob/show.html'); const form = $('.js-upload-blob-form'); this.blobFileDropzone = new BlobFileDropzone(form, 'POST'); this.dropzone = $('.js-upload-blob-form .dropzone').get(0).dropzone; diff --git a/spec/javascripts/blob/notebook/index_spec.js b/spec/javascripts/blob/notebook/index_spec.js index 28d3b2f5ea3..6bb5bac007f 100644 --- a/spec/javascripts/blob/notebook/index_spec.js +++ b/spec/javascripts/blob/notebook/index_spec.js @@ -3,10 +3,10 @@ import axios from '~/lib/utils/axios_utils'; import renderNotebook from '~/blob/notebook'; describe('iPython notebook renderer', () => { - preloadFixtures('static/notebook_viewer.html.raw'); + preloadFixtures('static/notebook_viewer.html'); beforeEach(() => { - loadFixtures('static/notebook_viewer.html.raw'); + loadFixtures('static/notebook_viewer.html'); }); it('shows loading icon', () => { diff --git a/spec/javascripts/blob/pdf/index_spec.js b/spec/javascripts/blob/pdf/index_spec.js index be917a0613f..acf87580777 100644 --- a/spec/javascripts/blob/pdf/index_spec.js +++ b/spec/javascripts/blob/pdf/index_spec.js @@ -15,10 +15,10 @@ describe('PDF renderer', () => { } }; - preloadFixtures('static/pdf_viewer.html.raw'); + preloadFixtures('static/pdf_viewer.html'); beforeEach(() => { - loadFixtures('static/pdf_viewer.html.raw'); + loadFixtures('static/pdf_viewer.html'); viewer = document.getElementById('js-pdf-viewer'); viewer.dataset.endpoint = testPDF; }); diff --git a/spec/javascripts/blob/sketch/index_spec.js b/spec/javascripts/blob/sketch/index_spec.js index 2b1e81e9cbc..3d3129e10da 100644 --- a/spec/javascripts/blob/sketch/index_spec.js +++ b/spec/javascripts/blob/sketch/index_spec.js @@ -13,10 +13,10 @@ describe('Sketch viewer', () => { }); }; - preloadFixtures('static/sketch_viewer.html.raw'); + preloadFixtures('static/sketch_viewer.html'); beforeEach(() => { - loadFixtures('static/sketch_viewer.html.raw'); + loadFixtures('static/sketch_viewer.html'); }); describe('with error message', () => { diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js index 93a942fe8d4..4ac15ca5aa2 100644 --- a/spec/javascripts/blob/viewer/index_spec.js +++ b/spec/javascripts/blob/viewer/index_spec.js @@ -9,12 +9,12 @@ describe('Blob viewer', () => { let blob; let mock; - preloadFixtures('snippets/show.html.raw'); + preloadFixtures('snippets/show.html'); beforeEach(() => { mock = new MockAdapter(axios); - loadFixtures('snippets/show.html.raw'); + loadFixtures('snippets/show.html'); $('#modal-upload-blob').remove(); blob = new BlobViewer(); diff --git a/spec/javascripts/boards/components/board_spec.js b/spec/javascripts/boards/components/board_spec.js index dee7841c088..6e6b3e6950b 100644 --- a/spec/javascripts/boards/components/board_spec.js +++ b/spec/javascripts/boards/components/board_spec.js @@ -9,7 +9,7 @@ describe('Board component', () => { let el; beforeEach(done => { - loadFixtures('boards/show.html.raw'); + loadFixtures('boards/show.html'); el = document.createElement('div'); document.body.appendChild(el); diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js b/spec/javascripts/bootstrap_linked_tabs_spec.js index c3e3d78ff63..1d21637ceae 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js @@ -1,10 +1,10 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs'; describe('Linked Tabs', () => { - preloadFixtures('static/linked_tabs.html.raw'); + preloadFixtures('static/linked_tabs.html'); beforeEach(() => { - loadFixtures('static/linked_tabs.html.raw'); + loadFixtures('static/linked_tabs.html'); }); describe('when is initialized', () => { diff --git a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js index 1fc0e206d5e..481b1a4d4b0 100644 --- a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js @@ -7,8 +7,8 @@ const VARIABLE_PATCH_ENDPOINT = 'http://test.host/frontend-fixtures/builds-proje const HIDE_CLASS = 'hide'; describe('AjaxFormVariableList', () => { - preloadFixtures('projects/ci_cd_settings.html.raw'); - preloadFixtures('projects/ci_cd_settings_with_variables.html.raw'); + preloadFixtures('projects/ci_cd_settings.html'); + preloadFixtures('projects/ci_cd_settings_with_variables.html'); let container; let saveButton; @@ -18,7 +18,7 @@ describe('AjaxFormVariableList', () => { let ajaxVariableList; beforeEach(() => { - loadFixtures('projects/ci_cd_settings.html.raw'); + loadFixtures('projects/ci_cd_settings.html'); container = document.querySelector('.js-ci-variable-list-section'); mock = new MockAdapter(axios); @@ -168,7 +168,7 @@ describe('AjaxFormVariableList', () => { describe('updateRowsWithPersistedVariables', () => { beforeEach(() => { - loadFixtures('projects/ci_cd_settings_with_variables.html.raw'); + loadFixtures('projects/ci_cd_settings_with_variables.html'); container = document.querySelector('.js-ci-variable-list-section'); const ajaxVariableListEl = document.querySelector('.js-ci-variable-list-section'); diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js index bef59b86d0c..70f49469300 100644 --- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js @@ -5,9 +5,9 @@ import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; const HIDE_CLASS = 'hide'; describe('VariableList', () => { - preloadFixtures('pipeline_schedules/edit.html.raw'); - preloadFixtures('pipeline_schedules/edit_with_variables.html.raw'); - preloadFixtures('projects/ci_cd_settings.html.raw'); + preloadFixtures('pipeline_schedules/edit.html'); + preloadFixtures('pipeline_schedules/edit_with_variables.html'); + preloadFixtures('projects/ci_cd_settings.html'); let $wrapper; let variableList; @@ -15,7 +15,7 @@ describe('VariableList', () => { describe('with only key/value inputs', () => { describe('with no variables', () => { beforeEach(() => { - loadFixtures('pipeline_schedules/edit.html.raw'); + loadFixtures('pipeline_schedules/edit.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ @@ -82,7 +82,7 @@ describe('VariableList', () => { describe('with persisted variables', () => { beforeEach(() => { - loadFixtures('pipeline_schedules/edit_with_variables.html.raw'); + loadFixtures('pipeline_schedules/edit_with_variables.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ @@ -115,7 +115,7 @@ describe('VariableList', () => { describe('with all inputs(key, value, protected)', () => { beforeEach(() => { - loadFixtures('projects/ci_cd_settings.html.raw'); + loadFixtures('projects/ci_cd_settings.html'); $wrapper = $('.js-ci-variable-list-section'); $wrapper.find('.js-ci-variable-input-protected').attr('data-default', 'false'); @@ -149,7 +149,7 @@ describe('VariableList', () => { describe('toggleEnableRow method', () => { beforeEach(() => { - loadFixtures('pipeline_schedules/edit_with_variables.html.raw'); + loadFixtures('pipeline_schedules/edit_with_variables.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ @@ -198,7 +198,7 @@ describe('VariableList', () => { describe('hideValues', () => { beforeEach(() => { - loadFixtures('projects/ci_cd_settings.html.raw'); + loadFixtures('projects/ci_cd_settings.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ diff --git a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js index 997d0d54d79..4982b68fa81 100644 --- a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js @@ -2,12 +2,12 @@ import $ from 'jquery'; import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list'; describe('NativeFormVariableList', () => { - preloadFixtures('pipeline_schedules/edit.html.raw'); + preloadFixtures('pipeline_schedules/edit.html'); let $wrapper; beforeEach(() => { - loadFixtures('pipeline_schedules/edit.html.raw'); + loadFixtures('pipeline_schedules/edit.html'); $wrapper = $('.js-ci-variable-list-section'); setupNativeFormVariableList({ diff --git a/spec/javascripts/clusters/clusters_bundle_spec.js b/spec/javascripts/clusters/clusters_bundle_spec.js index 71f16dc259e..0d3dcc29f22 100644 --- a/spec/javascripts/clusters/clusters_bundle_spec.js +++ b/spec/javascripts/clusters/clusters_bundle_spec.js @@ -9,10 +9,10 @@ import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; describe('Clusters', () => { let cluster; - preloadFixtures('clusters/show_cluster.html.raw'); + preloadFixtures('clusters/show_cluster.html'); beforeEach(() => { - loadFixtures('clusters/show_cluster.html.raw'); + loadFixtures('clusters/show_cluster.html'); cluster = new Clusters(); }); diff --git a/spec/javascripts/clusters/components/applications_spec.js b/spec/javascripts/clusters/components/applications_spec.js index 790e4b9602c..0f8153ad493 100644 --- a/spec/javascripts/clusters/components/applications_spec.js +++ b/spec/javascripts/clusters/components/applications_spec.js @@ -79,7 +79,7 @@ describe('Applications', () => { }); it('renders a row for GitLab Runner', () => { - expect(vm.$el.querySelector('.js-cluster-application-row-runner')).toBeNull(); + expect(vm.$el.querySelector('.js-cluster-application-row-runner')).not.toBeNull(); }); it('renders a row for Jupyter', () => { diff --git a/spec/javascripts/collapsed_sidebar_todo_spec.js b/spec/javascripts/collapsed_sidebar_todo_spec.js index dc5737558c0..bb90e53e525 100644 --- a/spec/javascripts/collapsed_sidebar_todo_spec.js +++ b/spec/javascripts/collapsed_sidebar_todo_spec.js @@ -6,7 +6,7 @@ import Sidebar from '~/right_sidebar'; import timeoutPromise from './helpers/set_timeout_promise_helper'; describe('Issuable right sidebar collapsed todo toggle', () => { - const fixtureName = 'issues/open-issue.html.raw'; + const fixtureName = 'issues/open-issue.html'; const jsonFixtureName = 'todos/todos.json'; let mock; diff --git a/spec/javascripts/create_item_dropdown_spec.js b/spec/javascripts/create_item_dropdown_spec.js index 9cf72d7c55b..a814952faab 100644 --- a/spec/javascripts/create_item_dropdown_spec.js +++ b/spec/javascripts/create_item_dropdown_spec.js @@ -20,7 +20,7 @@ const DROPDOWN_ITEM_DATA = [ ]; describe('CreateItemDropdown', () => { - preloadFixtures('static/create_item_dropdown.html.raw'); + preloadFixtures('static/create_item_dropdown.html'); let $wrapperEl; let createItemDropdown; @@ -44,7 +44,7 @@ describe('CreateItemDropdown', () => { } beforeEach(() => { - loadFixtures('static/create_item_dropdown.html.raw'); + loadFixtures('static/create_item_dropdown.html'); $wrapperEl = $('.js-create-item-dropdown-fixture-root'); }); diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js b/spec/javascripts/filtered_search/dropdown_user_spec.js index e8fcc8592eb..f764800fff0 100644 --- a/spec/javascripts/filtered_search/dropdown_user_spec.js +++ b/spec/javascripts/filtered_search/dropdown_user_spec.js @@ -72,7 +72,7 @@ describe('Dropdown User', () => { }); describe('hideCurrentUser', () => { - const fixtureTemplate = 'issues/issue_list.html.raw'; + const fixtureTemplate = 'issues/issue_list.html'; preloadFixtures(fixtureTemplate); let dropdown; diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js index cfd0b96ec43..62d1bd69635 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js @@ -4,7 +4,7 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; describe('Dropdown Utils', () => { - const issueListFixture = 'issues/issue_list.html.raw'; + const issueListFixture = 'issues/issue_list.html'; preloadFixtures(issueListFixture); describe('getEscapedText', () => { diff --git a/spec/javascripts/fixtures/.gitignore b/spec/javascripts/fixtures/.gitignore index 0c35cdd778e..2507c8e7263 100644 --- a/spec/javascripts/fixtures/.gitignore +++ b/spec/javascripts/fixtures/.gitignore @@ -1,2 +1,3 @@ *.html.raw +*.html *.json diff --git a/spec/javascripts/fixtures/abuse_reports.rb b/spec/javascripts/fixtures/abuse_reports.rb index 387858cba77..54b6419bcdb 100644 --- a/spec/javascripts/fixtures/abuse_reports.rb +++ b/spec/javascripts/fixtures/abuse_reports.rb @@ -18,7 +18,7 @@ describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :controll sign_in(admin) end - it 'abuse_reports/abuse_reports_list.html.raw' do |example| + it 'abuse_reports/abuse_reports_list.html' do |example| get :index expect(response).to be_success diff --git a/spec/javascripts/fixtures/admin_users.rb b/spec/javascripts/fixtures/admin_users.rb index 9989ac4fff2..76dbdf603da 100644 --- a/spec/javascripts/fixtures/admin_users.rb +++ b/spec/javascripts/fixtures/admin_users.rb @@ -17,7 +17,7 @@ describe Admin::UsersController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('admin/users') end - it 'admin/users/new_with_internal_user_regex.html.raw' do |example| + it 'admin/users/new_with_internal_user_regex.html' do |example| stub_application_setting(user_default_external: true) stub_application_setting(user_default_internal_regex: '^(?:(?!\.ext@).)*$\r?') diff --git a/spec/javascripts/fixtures/application_settings.rb b/spec/javascripts/fixtures/application_settings.rb index a9d3043f73d..c535e598e12 100644 --- a/spec/javascripts/fixtures/application_settings.rb +++ b/spec/javascripts/fixtures/application_settings.rb @@ -23,7 +23,7 @@ describe Admin::ApplicationSettingsController, '(JavaScript fixtures)', type: :c remove_repository(project) end - it 'application_settings/accounts_and_limit.html.raw' do |example| + it 'application_settings/accounts_and_limit.html' do |example| stub_application_setting(user_default_external: false) get :show diff --git a/spec/javascripts/fixtures/blob.rb b/spec/javascripts/fixtures/blob.rb index cd66d98f92a..db7749bc000 100644 --- a/spec/javascripts/fixtures/blob.rb +++ b/spec/javascripts/fixtures/blob.rb @@ -22,7 +22,7 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'blob/show.html.raw' do |example| + it 'blob/show.html' do |example| get(:show, params: { namespace_id: project.namespace, project_id: project, diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb index 1d675e008ba..c4390e89578 100644 --- a/spec/javascripts/fixtures/boards.rb +++ b/spec/javascripts/fixtures/boards.rb @@ -17,7 +17,7 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller sign_in(admin) end - it 'boards/show.html.raw' do |example| + it 'boards/show.html' do |example| get(:index, params: { namespace_id: project.namespace, project_id: project diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb index 3cc713ef90f..5d2d6c7ec0e 100644 --- a/spec/javascripts/fixtures/branches.rb +++ b/spec/javascripts/fixtures/branches.rb @@ -21,7 +21,7 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'branches/new_branch.html.raw' do |example| + it 'branches/new_branch.html' do |example| get :new, params: { namespace_id: project.namespace.to_param, project_id: project diff --git a/spec/javascripts/fixtures/clusters.rb b/spec/javascripts/fixtures/clusters.rb index 69dbe54ffc2..8ebd8a41366 100644 --- a/spec/javascripts/fixtures/clusters.rb +++ b/spec/javascripts/fixtures/clusters.rb @@ -22,7 +22,7 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'clusters/show_cluster.html.raw' do |example| + it 'clusters/show_cluster.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, project_id: project, diff --git a/spec/javascripts/fixtures/commit.rb b/spec/javascripts/fixtures/commit.rb index 295f13b34a4..ab10f559e4b 100644 --- a/spec/javascripts/fixtures/commit.rb +++ b/spec/javascripts/fixtures/commit.rb @@ -19,7 +19,7 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller allow(SecureRandom).to receive(:hex).and_return('securerandomhex:thereisnospoon') end - it 'commit/show.html.raw' do |example| + it 'commit/show.html' do |example| params = { namespace_id: project.namespace, project_id: project, diff --git a/spec/javascripts/fixtures/groups.rb b/spec/javascripts/fixtures/groups.rb index 03136f4e661..16e31028b05 100644 --- a/spec/javascripts/fixtures/groups.rb +++ b/spec/javascripts/fixtures/groups.rb @@ -18,7 +18,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do end describe GroupsController, '(JavaScript fixtures)', type: :controller do - it 'groups/edit.html.raw' do |example| + it 'groups/edit.html' do |example| get :edit, params: { id: group } expect(response).to be_success @@ -27,7 +27,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do end describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do - it 'groups/ci_cd_settings.html.raw' do |example| + it 'groups/ci_cd_settings.html' do |example| get :show, params: { group_id: group } expect(response).to be_success diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb index 9b8e90c2a43..645b3aa788a 100644 --- a/spec/javascripts/fixtures/issues.rb +++ b/spec/javascripts/fixtures/issues.rb @@ -21,26 +21,26 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller remove_repository(project) end - it 'issues/open-issue.html.raw' do |example| + it 'issues/open-issue.html' do |example| render_issue(example.description, create(:issue, project: project)) end - it 'issues/closed-issue.html.raw' do |example| + it 'issues/closed-issue.html' do |example| render_issue(example.description, create(:closed_issue, project: project)) end - it 'issues/issue-with-task-list.html.raw' do |example| + it 'issues/issue-with-task-list.html' do |example| issue = create(:issue, project: project, description: '- [ ] Task List Item') render_issue(example.description, issue) end - it 'issues/issue_with_comment.html.raw' do |example| + it 'issues/issue_with_comment.html' do |example| issue = create(:issue, project: project) create(:note, project: project, noteable: issue, note: '- [ ] Task List Item').save render_issue(example.description, issue) end - it 'issues/issue_list.html.raw' do |example| + it 'issues/issue_list.html' do |example| create(:issue, project: project) get :index, params: { diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb index 433bb690a1c..941235190b5 100644 --- a/spec/javascripts/fixtures/jobs.rb +++ b/spec/javascripts/fixtures/jobs.rb @@ -32,7 +32,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'builds/build-with-artifacts.html.raw' do |example| + it 'builds/build-with-artifacts.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, project_id: project, diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index eb37be87e1d..7df1e5cb512 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -42,19 +42,19 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont remove_repository(project) end - it 'merge_requests/merge_request_of_current_user.html.raw' do |example| + it 'merge_requests/merge_request_of_current_user.html' do |example| merge_request.update(author: admin) render_merge_request(example.description, merge_request) end - it 'merge_requests/merge_request_with_task_list.html.raw' do |example| + it 'merge_requests/merge_request_with_task_list.html' do |example| create(:ci_build, :pending, pipeline: pipeline) render_merge_request(example.description, merge_request) end - it 'merge_requests/merged_merge_request.html.raw' do |example| + it 'merge_requests/merged_merge_request.html' do |example| expect_next_instance_of(MergeRequest) do |merge_request| allow(merge_request).to receive(:source_branch_exists?).and_return(true) allow(merge_request).to receive(:can_remove_source_branch?).and_return(true) @@ -62,13 +62,13 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont render_merge_request(example.description, merged_merge_request) end - it 'merge_requests/diff_comment.html.raw' do |example| + it 'merge_requests/diff_comment.html' do |example| create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) create(:note_on_merge_request, author: admin, project: project, noteable: merge_request) render_merge_request(example.description, merge_request) end - it 'merge_requests/merge_request_with_comment.html.raw' do |example| + it 'merge_requests/merge_request_with_comment.html' do |example| create(:note_on_merge_request, author: admin, project: project, noteable: merge_request, note: '- [ ] Task List Item') render_merge_request(example.description, merge_request) end diff --git a/spec/javascripts/fixtures/pipeline_schedules.rb b/spec/javascripts/fixtures/pipeline_schedules.rb index 05d79ec8de9..e5176a58273 100644 --- a/spec/javascripts/fixtures/pipeline_schedules.rb +++ b/spec/javascripts/fixtures/pipeline_schedules.rb @@ -21,7 +21,7 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : sign_in(admin) end - it 'pipeline_schedules/edit.html.raw' do |example| + it 'pipeline_schedules/edit.html' do |example| get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -32,7 +32,7 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : store_frontend_fixture(response, example.description) end - it 'pipeline_schedules/edit_with_variables.html.raw' do |example| + it 'pipeline_schedules/edit_with_variables.html' do |example| get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index 85f02923804..446da83a7f9 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -28,7 +28,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do end describe ProjectsController, '(JavaScript fixtures)', type: :controller do - it 'projects/dashboard.html.raw' do |example| + it 'projects/dashboard.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, id: project @@ -38,7 +38,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do store_frontend_fixture(response, example.description) end - it 'projects/overview.html.raw' do |example| + it 'projects/overview.html' do |example| get :show, params: { namespace_id: project_with_repo.namespace.to_param, id: project_with_repo @@ -48,7 +48,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do store_frontend_fixture(response, example.description) end - it 'projects/edit.html.raw' do |example| + it 'projects/edit.html' do |example| get :edit, params: { namespace_id: project.namespace.to_param, id: project @@ -60,7 +60,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do end describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do - it 'projects/ci_cd_settings.html.raw' do |example| + it 'projects/ci_cd_settings.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, project_id: project @@ -70,7 +70,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do store_frontend_fixture(response, example.description) end - it 'projects/ci_cd_settings_with_variables.html.raw' do |example| + it 'projects/ci_cd_settings_with_variables.html' do |example| create(:ci_variable, project: project_variable_populated) create(:ci_variable, project: project_variable_populated) diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb index 746fbfd66dd..29dc95305b7 100644 --- a/spec/javascripts/fixtures/prometheus_service.rb +++ b/spec/javascripts/fixtures/prometheus_service.rb @@ -22,7 +22,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'services/prometheus/prometheus_service.html.raw' do |example| + it 'services/prometheus/prometheus_service.html' do |example| get :edit, params: { namespace_id: namespace, project_id: project, diff --git a/spec/javascripts/fixtures/search.rb b/spec/javascripts/fixtures/search.rb index 703cd3d49fa..5f5b4d4e60d 100644 --- a/spec/javascripts/fixtures/search.rb +++ b/spec/javascripts/fixtures/search.rb @@ -9,7 +9,7 @@ describe SearchController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('search/') end - it 'search/show.html.raw' do |example| + it 'search/show.html' do |example| get :show expect(response).to be_success diff --git a/spec/javascripts/fixtures/services.rb b/spec/javascripts/fixtures/services.rb index 6ccd74a07ff..dc7ee484c22 100644 --- a/spec/javascripts/fixtures/services.rb +++ b/spec/javascripts/fixtures/services.rb @@ -22,7 +22,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'services/edit_service.html.raw' do |example| + it 'services/edit_service.html' do |example| get :edit, params: { namespace_id: namespace, project_id: project, diff --git a/spec/javascripts/fixtures/sessions.rb b/spec/javascripts/fixtures/sessions.rb index e90a58e8c54..8656dea696a 100644 --- a/spec/javascripts/fixtures/sessions.rb +++ b/spec/javascripts/fixtures/sessions.rb @@ -16,7 +16,7 @@ describe 'Sessions (JavaScript fixtures)' do set_devise_mapping(context: @request) end - it 'sessions/new.html.raw' do |example| + it 'sessions/new.html' do |example| get :new expect(response).to be_success diff --git a/spec/javascripts/fixtures/snippet.rb b/spec/javascripts/fixtures/snippet.rb index bcd6546f3df..ebc5b793166 100644 --- a/spec/javascripts/fixtures/snippet.rb +++ b/spec/javascripts/fixtures/snippet.rb @@ -23,7 +23,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'snippets/show.html.raw' do |example| + it 'snippets/show.html' do |example| create(:discussion_note_on_snippet, noteable: snippet, project: project, author: admin, note: '- [ ] Task List Item') get(:show, params: { id: snippet.to_param }) diff --git a/spec/javascripts/fixtures/static/ajax_loading_spinner.html.raw b/spec/javascripts/fixtures/static/ajax_loading_spinner.html index 0e1ebb32b1c..0e1ebb32b1c 100644 --- a/spec/javascripts/fixtures/static/ajax_loading_spinner.html.raw +++ b/spec/javascripts/fixtures/static/ajax_loading_spinner.html diff --git a/spec/javascripts/fixtures/static/balsamiq_viewer.html.raw b/spec/javascripts/fixtures/static/balsamiq_viewer.html index cdd723d1a84..cdd723d1a84 100644 --- a/spec/javascripts/fixtures/static/balsamiq_viewer.html.raw +++ b/spec/javascripts/fixtures/static/balsamiq_viewer.html diff --git a/spec/javascripts/fixtures/static/create_item_dropdown.html.raw b/spec/javascripts/fixtures/static/create_item_dropdown.html index d2d38370092..d2d38370092 100644 --- a/spec/javascripts/fixtures/static/create_item_dropdown.html.raw +++ b/spec/javascripts/fixtures/static/create_item_dropdown.html diff --git a/spec/javascripts/fixtures/static/event_filter.html.raw b/spec/javascripts/fixtures/static/event_filter.html index 8e9b6fb1b5c..8e9b6fb1b5c 100644 --- a/spec/javascripts/fixtures/static/event_filter.html.raw +++ b/spec/javascripts/fixtures/static/event_filter.html diff --git a/spec/javascripts/fixtures/static/gl_dropdown.html.raw b/spec/javascripts/fixtures/static/gl_dropdown.html index 08f6738414e..08f6738414e 100644 --- a/spec/javascripts/fixtures/static/gl_dropdown.html.raw +++ b/spec/javascripts/fixtures/static/gl_dropdown.html diff --git a/spec/javascripts/fixtures/static/gl_field_errors.html.raw b/spec/javascripts/fixtures/static/gl_field_errors.html index f8470e02b7c..f8470e02b7c 100644 --- a/spec/javascripts/fixtures/static/gl_field_errors.html.raw +++ b/spec/javascripts/fixtures/static/gl_field_errors.html diff --git a/spec/javascripts/fixtures/static/issuable_filter.html.raw b/spec/javascripts/fixtures/static/issuable_filter.html index 06b70fb43f1..06b70fb43f1 100644 --- a/spec/javascripts/fixtures/static/issuable_filter.html.raw +++ b/spec/javascripts/fixtures/static/issuable_filter.html diff --git a/spec/javascripts/fixtures/static/issue_sidebar_label.html.raw b/spec/javascripts/fixtures/static/issue_sidebar_label.html index ec8fb30f219..ec8fb30f219 100644 --- a/spec/javascripts/fixtures/static/issue_sidebar_label.html.raw +++ b/spec/javascripts/fixtures/static/issue_sidebar_label.html diff --git a/spec/javascripts/fixtures/static/line_highlighter.html.raw b/spec/javascripts/fixtures/static/line_highlighter.html index 897a25d6760..897a25d6760 100644 --- a/spec/javascripts/fixtures/static/line_highlighter.html.raw +++ b/spec/javascripts/fixtures/static/line_highlighter.html diff --git a/spec/javascripts/fixtures/static/linked_tabs.html.raw b/spec/javascripts/fixtures/static/linked_tabs.html index c25463bf1db..c25463bf1db 100644 --- a/spec/javascripts/fixtures/static/linked_tabs.html.raw +++ b/spec/javascripts/fixtures/static/linked_tabs.html diff --git a/spec/javascripts/fixtures/static/merge_requests_show.html.raw b/spec/javascripts/fixtures/static/merge_requests_show.html index e219d9462aa..e219d9462aa 100644 --- a/spec/javascripts/fixtures/static/merge_requests_show.html.raw +++ b/spec/javascripts/fixtures/static/merge_requests_show.html diff --git a/spec/javascripts/fixtures/static/mini_dropdown_graph.html.raw b/spec/javascripts/fixtures/static/mini_dropdown_graph.html index cd0b8dec3fc..cd0b8dec3fc 100644 --- a/spec/javascripts/fixtures/static/mini_dropdown_graph.html.raw +++ b/spec/javascripts/fixtures/static/mini_dropdown_graph.html diff --git a/spec/javascripts/fixtures/static/notebook_viewer.html.raw b/spec/javascripts/fixtures/static/notebook_viewer.html index 4bbb7bf1094..4bbb7bf1094 100644 --- a/spec/javascripts/fixtures/static/notebook_viewer.html.raw +++ b/spec/javascripts/fixtures/static/notebook_viewer.html diff --git a/spec/javascripts/fixtures/static/oauth_remember_me.html.raw b/spec/javascripts/fixtures/static/oauth_remember_me.html index 9ba1ffc72fe..9ba1ffc72fe 100644 --- a/spec/javascripts/fixtures/static/oauth_remember_me.html.raw +++ b/spec/javascripts/fixtures/static/oauth_remember_me.html diff --git a/spec/javascripts/fixtures/static/pdf_viewer.html.raw b/spec/javascripts/fixtures/static/pdf_viewer.html index 350d35a262f..350d35a262f 100644 --- a/spec/javascripts/fixtures/static/pdf_viewer.html.raw +++ b/spec/javascripts/fixtures/static/pdf_viewer.html diff --git a/spec/javascripts/fixtures/static/pipeline_graph.html.raw b/spec/javascripts/fixtures/static/pipeline_graph.html index 422372bb7d5..422372bb7d5 100644 --- a/spec/javascripts/fixtures/static/pipeline_graph.html.raw +++ b/spec/javascripts/fixtures/static/pipeline_graph.html diff --git a/spec/javascripts/fixtures/static/pipelines.html.raw b/spec/javascripts/fixtures/static/pipelines.html index 42333f94f2f..42333f94f2f 100644 --- a/spec/javascripts/fixtures/static/pipelines.html.raw +++ b/spec/javascripts/fixtures/static/pipelines.html diff --git a/spec/javascripts/fixtures/static/project_select_combo_button.html.raw b/spec/javascripts/fixtures/static/project_select_combo_button.html index 50c826051c0..50c826051c0 100644 --- a/spec/javascripts/fixtures/static/project_select_combo_button.html.raw +++ b/spec/javascripts/fixtures/static/project_select_combo_button.html diff --git a/spec/javascripts/fixtures/static/search_autocomplete.html.raw b/spec/javascripts/fixtures/static/search_autocomplete.html index 29db9020424..29db9020424 100644 --- a/spec/javascripts/fixtures/static/search_autocomplete.html.raw +++ b/spec/javascripts/fixtures/static/search_autocomplete.html diff --git a/spec/javascripts/fixtures/static/signin_tabs.html.raw b/spec/javascripts/fixtures/static/signin_tabs.html index 7e66ab9394b..7e66ab9394b 100644 --- a/spec/javascripts/fixtures/static/signin_tabs.html.raw +++ b/spec/javascripts/fixtures/static/signin_tabs.html diff --git a/spec/javascripts/fixtures/static/sketch_viewer.html.raw b/spec/javascripts/fixtures/static/sketch_viewer.html index e25e554e568..e25e554e568 100644 --- a/spec/javascripts/fixtures/static/sketch_viewer.html.raw +++ b/spec/javascripts/fixtures/static/sketch_viewer.html diff --git a/spec/javascripts/fixtures/static_fixtures.rb b/spec/javascripts/fixtures/static_fixtures.rb index b5188eeb994..cb4b90cdca5 100644 --- a/spec/javascripts/fixtures/static_fixtures.rb +++ b/spec/javascripts/fixtures/static_fixtures.rb @@ -4,7 +4,7 @@ describe ApplicationController, '(Static JavaScript fixtures)', type: :controlle include JavaScriptFixturesHelpers Dir.glob('{,ee/}spec/javascripts/fixtures/**/*.haml').map do |file_path| - it "static/#{file_path.sub(%r{\A(ee/)?spec/javascripts/fixtures/}, '').sub(/\.haml\z/, '.raw')}" do |example| + it "static/#{file_path.sub(%r{\A(ee/)?spec/javascripts/fixtures/}, '').sub(/\.haml\z/, '')}" do |example| store_frontend_fixture(render_template(file_path), example.description) end end diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index b5f6620873b..6e37a2e5a4c 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -26,7 +26,7 @@ describe 'Todos (JavaScript fixtures)' do sign_in(admin) end - it 'todos/todos.html.raw' do |example| + it 'todos/todos.html' do |example| get :index expect(response).to be_success diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb index 5cdbadef639..15866d65a4f 100644 --- a/spec/javascripts/fixtures/u2f.rb +++ b/spec/javascripts/fixtures/u2f.rb @@ -18,7 +18,7 @@ context 'U2F' do set_devise_mapping(context: @request) end - it 'u2f/authenticate.html.raw' do |example| + it 'u2f/authenticate.html' do |example| allow(controller).to receive(:find_user).and_return(user) post :create, params: { user: { login: user.username, password: user.password } } @@ -36,7 +36,7 @@ context 'U2F' do allow_any_instance_of(Profiles::TwoFactorAuthsController).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares') end - it 'u2f/register.html.raw' do |example| + it 'u2f/register.html' do |example| get :show expect(response).to be_success diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 85083653db8..57e31d933ca 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -5,7 +5,7 @@ import GLDropdown from '~/gl_dropdown'; import '~/lib/utils/common_utils'; describe('glDropdown', function describeDropdown() { - preloadFixtures('static/gl_dropdown.html.raw'); + preloadFixtures('static/gl_dropdown.html'); loadJSONFixtures('projects.json'); const NON_SELECTABLE_CLASSES = @@ -64,7 +64,7 @@ describe('glDropdown', function describeDropdown() { } beforeEach(() => { - loadFixtures('static/gl_dropdown.html.raw'); + loadFixtures('static/gl_dropdown.html'); this.dropdownContainerElement = $('.dropdown.inline'); this.$dropdownMenuElement = $('.dropdown-menu', this.dropdownContainerElement); this.projectsData = getJSONFixture('projects.json'); diff --git a/spec/javascripts/gl_field_errors_spec.js b/spec/javascripts/gl_field_errors_spec.js index b463c9afbee..294f219d6fe 100644 --- a/spec/javascripts/gl_field_errors_spec.js +++ b/spec/javascripts/gl_field_errors_spec.js @@ -4,10 +4,10 @@ import $ from 'jquery'; import GlFieldErrors from '~/gl_field_errors'; describe('GL Style Field Errors', function() { - preloadFixtures('static/gl_field_errors.html.raw'); + preloadFixtures('static/gl_field_errors.html'); beforeEach(function() { - loadFixtures('static/gl_field_errors.html.raw'); + loadFixtures('static/gl_field_errors.html'); const $form = $('form.gl-show-field-errors'); this.$form = $form; diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index 2fe34e5a76f..0ddf589f368 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -3,7 +3,7 @@ import initTodoToggle from '~/header'; describe('Header', function() { const todosPendingCount = '.todos-count'; - const fixtureTemplate = 'issues/open-issue.html.raw'; + const fixtureTemplate = 'issues/open-issue.html'; function isTodosCountHidden() { return $(todosPendingCount).hasClass('hidden'); diff --git a/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js b/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js index ffc2a4c9ddb..db1988be3e1 100644 --- a/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/radio_group_spec.js @@ -76,6 +76,7 @@ describe('IDE commit sidebar radio group', () => { const Component = Vue.extend(radioGroup); store.state.commit.commitAction = '1'; + store.state.commit.newBranchName = 'test-123'; vm = createComponentWithStore(Component, store, { value: '1', @@ -113,6 +114,12 @@ describe('IDE commit sidebar radio group', () => { done(); }); }); + + it('renders newBranchName if present', () => { + const input = vm.$el.querySelector('.form-control'); + + expect(input.value).toBe('test-123'); + }); }); describe('tooltipTitle', () => { diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js index 06b8b452319..34d97347438 100644 --- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js @@ -396,7 +396,7 @@ describe('IDE commit module actions', () => { .then(() => { expect(visitUrl).toHaveBeenCalledWith( `webUrl/merge_requests/new?merge_request[source_branch]=${ - store.getters['commit/newBranchName'] + store.getters['commit/placeholderBranchName'] }&merge_request[target_branch]=master`, ); diff --git a/spec/javascripts/ide/stores/modules/commit/getters_spec.js b/spec/javascripts/ide/stores/modules/commit/getters_spec.js index 3f4bf407a1f..702e78ef773 100644 --- a/spec/javascripts/ide/stores/modules/commit/getters_spec.js +++ b/spec/javascripts/ide/stores/modules/commit/getters_spec.js @@ -29,11 +29,11 @@ describe('IDE commit module getters', () => { }); }); - describe('newBranchName', () => { + describe('placeholderBranchName', () => { it('includes username, currentBranchId, patch & random number', () => { gon.current_username = 'username'; - const branch = getters.newBranchName(state, null, { + const branch = getters.placeholderBranchName(state, null, { currentBranchId: 'testing', }); @@ -46,7 +46,7 @@ describe('IDE commit module getters', () => { currentBranchId: 'master', }; const localGetters = { - newBranchName: 'newBranchName', + placeholderBranchName: 'newBranchName', }; beforeEach(() => { @@ -71,7 +71,7 @@ describe('IDE commit module getters', () => { expect(getters.branchName(state, localGetters, rootState)).toBe('state-newBranchName'); }); - it('uses getters newBranchName when state newBranchName is empty', () => { + it('uses placeholderBranchName when state newBranchName is empty', () => { Object.assign(state, { newBranchName: '', }); diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js index 4f4c9a7b463..069e2cb07b5 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/javascripts/integrations/integration_settings_form_spec.js @@ -4,7 +4,7 @@ import axios from '~/lib/utils/axios_utils'; import IntegrationSettingsForm from '~/integrations/integration_settings_form'; describe('IntegrationSettingsForm', () => { - const FIXTURE = 'services/edit_service.html.raw'; + const FIXTURE = 'services/edit_service.html'; preloadFixtures(FIXTURE); beforeEach(() => { diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 7be495d1d35..11ab6c38a55 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -9,9 +9,9 @@ import '~/lib/utils/text_utility'; describe('Issue', function() { let $boxClosed, $boxOpen, $btn; - preloadFixtures('issues/closed-issue.html.raw'); - preloadFixtures('issues/issue-with-task-list.html.raw'); - preloadFixtures('issues/open-issue.html.raw'); + preloadFixtures('issues/closed-issue.html'); + preloadFixtures('issues/issue-with-task-list.html'); + preloadFixtures('issues/open-issue.html'); function expectErrorMessage() { const $flashMessage = $('div.flash-alert'); @@ -105,9 +105,9 @@ describe('Issue', function() { beforeEach(function() { if (isIssueInitiallyOpen) { - loadFixtures('issues/open-issue.html.raw'); + loadFixtures('issues/open-issue.html'); } else { - loadFixtures('issues/closed-issue.html.raw'); + loadFixtures('issues/closed-issue.html'); } mock = new MockAdapter(axios); diff --git a/spec/javascripts/jobs/components/commit_block_spec.js b/spec/javascripts/jobs/components/commit_block_spec.js index 98eba3ac976..c02f564d01a 100644 --- a/spec/javascripts/jobs/components/commit_block_spec.js +++ b/spec/javascripts/jobs/components/commit_block_spec.js @@ -9,6 +9,7 @@ describe('Commit block', () => { const props = { commit: { short_id: '1f0fb84f', + id: '1f0fb84fb6770d74d97eee58118fd3909cd4f48c', commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c', title: 'Update README.md', }, @@ -42,7 +43,7 @@ describe('Commit block', () => { it('renders clipboard button', () => { expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual( - props.commit.short_id, + props.commit.id, ); }); }); diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js index e5678ee5379..ccf439aac74 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js +++ b/spec/javascripts/labels_issue_sidebar_spec.js @@ -16,10 +16,10 @@ let saveLabelCount = 0; let mock; describe('Issue dropdown sidebar', () => { - preloadFixtures('static/issue_sidebar_label.html.raw'); + preloadFixtures('static/issue_sidebar_label.html'); beforeEach(() => { - loadFixtures('static/issue_sidebar_label.html.raw'); + loadFixtures('static/issue_sidebar_label.html'); mock = new MockAdapter(axios); diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js index cbdc1644430..f3fb792c62d 100644 --- a/spec/javascripts/lazy_loader_spec.js +++ b/spec/javascripts/lazy_loader_spec.js @@ -11,11 +11,11 @@ const execImmediately = callback => { describe('LazyLoader', function() { let lazyLoader = null; - preloadFixtures('issues/issue_with_comment.html.raw'); + preloadFixtures('issues/issue_with_comment.html'); describe('without IntersectionObserver', () => { beforeEach(function() { - loadFixtures('issues/issue_with_comment.html.raw'); + loadFixtures('issues/issue_with_comment.html'); lazyLoader = new LazyLoader({ observerNode: 'foobar', @@ -131,7 +131,7 @@ describe('LazyLoader', function() { describe('with IntersectionObserver', () => { beforeEach(function() { - loadFixtures('issues/issue_with_comment.html.raw'); + loadFixtures('issues/issue_with_comment.html'); lazyLoader = new LazyLoader({ observerNode: 'foobar', diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index 4eea364bd69..a75470b4db8 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -5,7 +5,7 @@ import LineHighlighter from '~/line_highlighter'; describe('LineHighlighter', function() { var clickLine; - preloadFixtures('static/line_highlighter.html.raw'); + preloadFixtures('static/line_highlighter.html'); clickLine = function(number, eventData = {}) { if ($.isEmptyObject(eventData)) { return $('#L' + number).click(); @@ -15,7 +15,7 @@ describe('LineHighlighter', function() { } }; beforeEach(function() { - loadFixtures('static/line_highlighter.html.raw'); + loadFixtures('static/line_highlighter.html'); this['class'] = new LineHighlighter(); this.css = this['class'].highlightLineClass; return (this.spies = { diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index ab809930804..431798c6ec3 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -11,9 +11,9 @@ describe('MergeRequest', function() { describe('task lists', function() { let mock; - preloadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + preloadFixtures('merge_requests/merge_request_with_task_list.html'); beforeEach(function() { - loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html'); spyOn(axios, 'patch').and.callThrough(); mock = new MockAdapter(axios); @@ -125,7 +125,7 @@ describe('MergeRequest', function() { describe('hideCloseButton', () => { describe('merge request of another user', () => { beforeEach(() => { - loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html'); this.el = document.querySelector('.js-issuable-actions'); new MergeRequest(); // eslint-disable-line no-new MergeRequest.hideCloseButton(); @@ -145,7 +145,7 @@ describe('MergeRequest', function() { describe('merge request of current_user', () => { beforeEach(() => { - loadFixtures('merge_requests/merge_request_of_current_user.html.raw'); + loadFixtures('merge_requests/merge_request_of_current_user.html'); this.el = document.querySelector('.js-issuable-actions'); MergeRequest.hideCloseButton(); }); diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index c8df05eccf5..1295d900de7 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -22,8 +22,8 @@ describe('MergeRequestTabs', function() { }; preloadFixtures( - 'merge_requests/merge_request_with_task_list.html.raw', - 'merge_requests/diff_comment.html.raw', + 'merge_requests/merge_request_with_task_list.html', + 'merge_requests/diff_comment.html', ); beforeEach(function() { @@ -48,7 +48,7 @@ describe('MergeRequestTabs', function() { var windowTarget = '_blank'; beforeEach(function() { - loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html'); tabUrl = $('.commits-tab a').attr('href'); }); diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js index 092ca9e1dab..aa4a376caf7 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js @@ -5,10 +5,10 @@ import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; import timeoutPromise from './helpers/set_timeout_promise_helper'; describe('Mini Pipeline Graph Dropdown', () => { - preloadFixtures('static/mini_dropdown_graph.html.raw'); + preloadFixtures('static/mini_dropdown_graph.html'); beforeEach(() => { - loadFixtures('static/mini_dropdown_graph.html.raw'); + loadFixtures('static/mini_dropdown_graph.html'); }); describe('When is initialized', () => { diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js index b1778029a77..6078a0e7872 100644 --- a/spec/javascripts/monitoring/dashboard_spec.js +++ b/spec/javascripts/monitoring/dashboard_spec.js @@ -98,7 +98,7 @@ describe('Dashboard', () => { }); }); - it('renders the dropdown with a number of environments', done => { + it('renders the environments dropdown with a number of environments', done => { const component = new DashboardComponent({ el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false }, @@ -107,14 +107,16 @@ describe('Dashboard', () => { component.store.storeEnvironmentsData(environmentData); setTimeout(() => { - const dropdownMenuEnvironments = component.$el.querySelectorAll('.dropdown-menu ul li a'); + const dropdownMenuEnvironments = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item', + ); expect(dropdownMenuEnvironments.length).toEqual(component.store.environmentsData.length); done(); }); }); - it('hides the dropdown list when there is no environments', done => { + it('hides the environments dropdown list when there is no environments', done => { const component = new DashboardComponent({ el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false }, @@ -123,14 +125,16 @@ describe('Dashboard', () => { component.store.storeEnvironmentsData([]); setTimeout(() => { - const dropdownMenuEnvironments = component.$el.querySelectorAll('.dropdown-menu ul'); + const dropdownMenuEnvironments = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item', + ); expect(dropdownMenuEnvironments.length).toEqual(0); done(); }); }); - it('renders the dropdown with a single is-active element', done => { + it('renders the environments dropdown with a single is-active element', done => { const component = new DashboardComponent({ el: document.querySelector('.prometheus-graphs'), propsData: { ...propsData, hasMetrics: true, showPanels: false }, @@ -139,14 +143,12 @@ describe('Dashboard', () => { component.store.storeEnvironmentsData(environmentData); setTimeout(() => { - const dropdownIsActiveElement = component.$el.querySelectorAll( - '.dropdown-menu ul li a.is-active', + const dropdownItems = component.$el.querySelectorAll( + '.js-environments-dropdown .dropdown-item[active="true"]', ); - expect(dropdownIsActiveElement.length).toEqual(1); - expect(dropdownIsActiveElement[0].textContent.trim()).toEqual( - component.currentEnvironmentName, - ); + expect(dropdownItems.length).toEqual(1); + expect(dropdownItems[0].textContent.trim()).toEqual(component.currentEnvironmentName); done(); }); }); diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 1d7b885e64f..4e3140ce4f1 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -3,7 +3,7 @@ import NewBranchForm from '~/new_branch_form'; describe('Branch', function() { describe('create a new branch', function() { - preloadFixtures('branches/new_branch.html.raw'); + preloadFixtures('branches/new_branch.html'); function fillNameWith(value) { $('.js-branch-name') @@ -16,7 +16,7 @@ describe('Branch', function() { } beforeEach(function() { - loadFixtures('branches/new_branch.html.raw'); + loadFixtures('branches/new_branch.html'); $('form').on('submit', function(e) { return e.preventDefault(); }); diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 7c869d4c326..3d2c617e479 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -34,7 +34,7 @@ const htmlEscape = comment => { describe('Notes', function() { const FLASH_TYPE_ALERT = 'alert'; const NOTES_POST_PATH = /(.*)\/notes\?html=true$/; - var fixture = 'snippets/show.html.raw'; + var fixture = 'snippets/show.html'; preloadFixtures(fixture); beforeEach(function() { diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js index 4125706a407..381be82697e 100644 --- a/spec/javascripts/oauth_remember_me_spec.js +++ b/spec/javascripts/oauth_remember_me_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me'; describe('OAuthRememberMe', () => { - preloadFixtures('static/oauth_remember_me.html.raw'); + preloadFixtures('static/oauth_remember_me.html'); beforeEach(() => { - loadFixtures('static/oauth_remember_me.html.raw'); + loadFixtures('static/oauth_remember_me.html'); new OAuthRememberMe({ container: $('#oauth-container') }).bindEvents(); }); diff --git a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js index 23d07056925..f7637964c60 100644 --- a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js +++ b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js @@ -3,7 +3,7 @@ import '~/lib/utils/text_utility'; import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports'; describe('Abuse Reports', () => { - const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw'; + const FIXTURE = 'abuse_reports/abuse_reports_list.html'; const MAX_MESSAGE_LENGTH = 500; let $messages; diff --git a/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js b/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js index 561bd2c96cb..6a239e307e9 100644 --- a/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js +++ b/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js @@ -5,7 +5,7 @@ import initUserInternalRegexPlaceholder, { } from '~/pages/admin/application_settings/account_and_limits'; describe('AccountAndLimits', () => { - const FIXTURE = 'application_settings/accounts_and_limit.html.raw'; + const FIXTURE = 'application_settings/accounts_and_limit.html'; let $userDefaultExternal; let $userInternalRegex; preloadFixtures(FIXTURE); diff --git a/spec/javascripts/pages/admin/users/new/index_spec.js b/spec/javascripts/pages/admin/users/new/index_spec.js index 5a849f34bc3..3896323eef7 100644 --- a/spec/javascripts/pages/admin/users/new/index_spec.js +++ b/spec/javascripts/pages/admin/users/new/index_spec.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import UserInternalRegexHandler from '~/pages/admin/users/new/index'; describe('UserInternalRegexHandler', () => { - const FIXTURE = 'admin/users/new_with_internal_user_regex.html.raw'; + const FIXTURE = 'admin/users/new_with_internal_user_regex.html'; let $userExternal; let $userEmail; let $warningMessage; diff --git a/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js b/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js index 7a8227479d4..1809e92e1d9 100644 --- a/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js +++ b/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import preserveUrlFragment from '~/pages/sessions/new/preserve_url_fragment'; describe('preserve_url_fragment', () => { - preloadFixtures('sessions/new.html.raw'); + preloadFixtures('sessions/new.html'); beforeEach(() => { - loadFixtures('sessions/new.html.raw'); + loadFixtures('sessions/new.html'); }); it('adds the url fragment to all login and sign up form actions', () => { diff --git a/spec/javascripts/pipelines_spec.js b/spec/javascripts/pipelines_spec.js index 6b86f9ea437..6d4d634c575 100644 --- a/spec/javascripts/pipelines_spec.js +++ b/spec/javascripts/pipelines_spec.js @@ -1,10 +1,10 @@ import Pipelines from '~/pipelines'; describe('Pipelines', () => { - preloadFixtures('static/pipeline_graph.html.raw'); + preloadFixtures('static/pipeline_graph.html'); beforeEach(() => { - loadFixtures('static/pipeline_graph.html.raw'); + loadFixtures('static/pipeline_graph.html'); }); it('should be defined', () => { diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js index 109a5000f5d..dc85292c23e 100644 --- a/spec/javascripts/project_select_combo_button_spec.js +++ b/spec/javascripts/project_select_combo_button_spec.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import ProjectSelectComboButton from '~/project_select_combo_button'; -const fixturePath = 'static/project_select_combo_button.html.raw'; +const fixturePath = 'static/project_select_combo_button.html'; describe('Project Select Combo Button', function() { preloadFixtures(fixturePath); diff --git a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js index 94e2f959d46..dca3e1553b9 100644 --- a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js +++ b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js @@ -5,7 +5,7 @@ import PANEL_STATE from '~/prometheus_metrics/constants'; import { metrics, missingVarMetrics } from './mock_data'; describe('PrometheusMetrics', () => { - const FIXTURE = 'services/prometheus/prometheus_service.html.raw'; + const FIXTURE = 'services/prometheus/prometheus_service.html'; preloadFixtures(FIXTURE); beforeEach(() => { diff --git a/spec/javascripts/read_more_spec.js b/spec/javascripts/read_more_spec.js index b1af0f80a50..d1d01272403 100644 --- a/spec/javascripts/read_more_spec.js +++ b/spec/javascripts/read_more_spec.js @@ -1,7 +1,7 @@ import initReadMore from '~/read_more'; describe('Read more click-to-expand functionality', () => { - const fixtureName = 'projects/overview.html.raw'; + const fixtureName = 'projects/overview.html'; preloadFixtures(fixtureName); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 992e17978c1..9565e3ce546 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -23,7 +23,7 @@ const assertSidebarState = function(state) { describe('RightSidebar', function() { describe('fixture tests', () => { - const fixtureName = 'issues/open-issue.html.raw'; + const fixtureName = 'issues/open-issue.html'; preloadFixtures(fixtureName); loadJSONFixtures('todos/todos.json'); let mock; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 7a4ca587313..ce7fa7a52ae 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -126,9 +126,9 @@ describe('Search autocomplete dropdown', () => { expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created"); }; - preloadFixtures('static/search_autocomplete.html.raw'); + preloadFixtures('static/search_autocomplete.html'); beforeEach(function() { - loadFixtures('static/search_autocomplete.html.raw'); + loadFixtures('static/search_autocomplete.html'); window.gon = {}; window.gon.current_user_id = userId; diff --git a/spec/javascripts/search_spec.js b/spec/javascripts/search_spec.js index 40bdbac7451..32f60508fa3 100644 --- a/spec/javascripts/search_spec.js +++ b/spec/javascripts/search_spec.js @@ -3,7 +3,7 @@ import Api from '~/api'; import Search from '~/pages/search/show/search'; describe('Search', () => { - const fixturePath = 'search/show.html.raw'; + const fixturePath = 'search/show.html'; const searchTerm = 'some search'; const fillDropdownInput = dropdownSelector => { const dropdownElement = document.querySelector(dropdownSelector).parentNode; diff --git a/spec/javascripts/settings_panels_spec.js b/spec/javascripts/settings_panels_spec.js index 3b681a9ff28..2c5d91a45bc 100644 --- a/spec/javascripts/settings_panels_spec.js +++ b/spec/javascripts/settings_panels_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import initSettingsPanels from '~/settings_panels'; describe('Settings Panels', () => { - preloadFixtures('groups/edit.html.raw'); + preloadFixtures('groups/edit.html'); beforeEach(() => { - loadFixtures('groups/edit.html.raw'); + loadFixtures('groups/edit.html'); }); describe('initSettingsPane', () => { diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js index 3ca6ecaa938..df7012bb659 100644 --- a/spec/javascripts/shortcuts_spec.js +++ b/spec/javascripts/shortcuts_spec.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import Shortcuts from '~/behaviors/shortcuts/shortcuts'; describe('Shortcuts', () => { - const fixtureName = 'snippets/show.html.raw'; + const fixtureName = 'snippets/show.html'; const createEvent = (type, target) => $.Event(type, { target, diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js index 3f0f67d71ca..016f5e033a5 100644 --- a/spec/javascripts/sidebar/sidebar_assignees_spec.js +++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js @@ -11,12 +11,12 @@ describe('sidebar assignees', () => { let vm; let mediator; let sidebarAssigneesEl; - preloadFixtures('issues/open-issue.html.raw'); + preloadFixtures('issues/open-issue.html'); beforeEach(() => { Vue.http.interceptors.push(Mock.sidebarMockInterceptor); - loadFixtures('issues/open-issue.html.raw'); + loadFixtures('issues/open-issue.html'); mediator = new SidebarMediator(Mock.mediator); spyOn(mediator, 'saveAssignees').and.callThrough(); diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js index 52da6a79939..ef5c774736b 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js +++ b/spec/javascripts/signin_tabs_memoizer_spec.js @@ -2,7 +2,7 @@ import AccessorUtilities from '~/lib/utils/accessor'; import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; describe('SigninTabsMemoizer', () => { - const fixtureTemplate = 'static/signin_tabs.html.raw'; + const fixtureTemplate = 'static/signin_tabs.html'; const tabSelector = 'ul.new-session-tabs'; const currentTabKey = 'current_signin_tab'; let memo; diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js index 69e43274250..802f54f6a7e 100644 --- a/spec/javascripts/todos_spec.js +++ b/spec/javascripts/todos_spec.js @@ -3,11 +3,11 @@ import Todos from '~/pages/dashboard/todos/index/todos'; import '~/lib/utils/common_utils'; describe('Todos', () => { - preloadFixtures('todos/todos.html.raw'); + preloadFixtures('todos/todos.html'); let todoItem; beforeEach(() => { - loadFixtures('todos/todos.html.raw'); + loadFixtures('todos/todos.html'); todoItem = document.querySelector('.todos-list .todo'); return new Todos(); diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index ddb09811dda..8f9cb270729 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -4,10 +4,10 @@ import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; describe('U2FAuthenticate', function() { - preloadFixtures('u2f/authenticate.html.raw'); + preloadFixtures('u2f/authenticate.html'); beforeEach(() => { - loadFixtures('u2f/authenticate.html.raw'); + loadFixtures('u2f/authenticate.html'); this.u2fDevice = new MockU2FDevice(); this.container = $('#js-authenticate-u2f'); this.component = new U2FAuthenticate( diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index 261db3d66d7..a75ceca9f4c 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -4,10 +4,10 @@ import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; describe('U2FRegister', function() { - preloadFixtures('u2f/register.html.raw'); + preloadFixtures('u2f/register.html'); beforeEach(done => { - loadFixtures('u2f/register.html.raw'); + loadFixtures('u2f/register.html'); this.u2fDevice = new MockU2FDevice(); this.container = $('#js-register-u2f'); this.component = new U2FRegister(this.container, $('#js-register-u2f-templates'), {}, 'token'); diff --git a/spec/javascripts/user_popovers_spec.js b/spec/javascripts/user_popovers_spec.js index b174a51c1a0..c0d5ee9c446 100644 --- a/spec/javascripts/user_popovers_spec.js +++ b/spec/javascripts/user_popovers_spec.js @@ -2,7 +2,7 @@ import initUserPopovers from '~/user_popovers'; import UsersCache from '~/lib/utils/users_cache'; describe('User Popovers', () => { - const fixtureTemplate = 'merge_requests/diff_comment.html.raw'; + const fixtureTemplate = 'merge_requests/diff_comment.html'; preloadFixtures(fixtureTemplate); const selector = '.js-user-link'; diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js index 30659ad16f3..368c997d318 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js @@ -415,7 +415,7 @@ describe('ReadyToMerge', () => { }); beforeEach(() => { - loadFixtures('merge_requests/merge_request_of_current_user.html.raw'); + loadFixtures('merge_requests/merge_request_of_current_user.html'); }); it('should call start and stop polling when MR merged', done => { diff --git a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js index e8b41e8eeff..852558a83bc 100644 --- a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js @@ -17,7 +17,7 @@ const DEFAULT_PROPS = { const UserPopover = Vue.extend(userPopover); describe('User Popover Component', () => { - const fixtureTemplate = 'merge_requests/diff_comment.html.raw'; + const fixtureTemplate = 'merge_requests/diff_comment.html'; preloadFixtures(fixtureTemplate); let vm; diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index e5f1e6ae937..8f662c71c7a 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -6,7 +6,7 @@ import ZenMode from '~/zen_mode'; describe('ZenMode', () => { let zen; let dropzoneForElementSpy; - const fixtureName = 'snippets/show.html.raw'; + const fixtureName = 'snippets/show.html'; preloadFixtures(fixtureName); diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb index 55c41e55437..72dfd6ff9ea 100644 --- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb @@ -30,6 +30,23 @@ describe Banzai::Filter::MergeRequestReferenceFilter do end end + describe 'all references' do + let(:doc) { reference_filter(merge.to_reference) } + let(:tag_el) { doc.css('a').first } + + it 'adds merge request iid' do + expect(tag_el["data-iid"]).to eq(merge.iid.to_s) + end + + it 'adds project data attribute with project id' do + expect(tag_el["data-project-path"]).to eq(project.full_path) + end + + it 'does not add `has-tooltip` class' do + expect(tag_el["class"]).not_to include('has-tooltip') + end + end + context 'internal reference' do let(:reference) { merge.to_reference } @@ -57,9 +74,9 @@ describe Banzai::Filter::MergeRequestReferenceFilter do expect(reference_filter(act).to_html).to eq exp end - it 'includes a title attribute' do + it 'has no title' do doc = reference_filter("Merge #{reference}") - expect(doc.css('a').first.attr('title')).to eq merge.title + expect(doc.css('a').first.attr('title')).to eq "" end it 'escapes the title attribute' do @@ -69,9 +86,9 @@ describe Banzai::Filter::MergeRequestReferenceFilter do expect(doc.text).to eq "Merge #{reference}" end - it 'includes default classes' do + it 'includes default classes, without tooltip' do doc = reference_filter("Merge #{reference}") - expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request has-tooltip' + expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request' end it 'includes a data-project attribute' do diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb index dcbd12fe190..b765c265e69 100644 --- a/spec/lib/gitlab/auth/o_auth/user_spec.rb +++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb @@ -207,6 +207,7 @@ describe Gitlab::Auth::OAuth::User do before do allow(ldap_user).to receive(:uid) { uid } allow(ldap_user).to receive(:username) { uid } + allow(ldap_user).to receive(:name) { 'John Doe' } allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:dn) { dn } end @@ -221,6 +222,7 @@ describe Gitlab::Auth::OAuth::User do it "creates a user with dual LDAP and omniauth identities" do expect(gl_user).to be_valid expect(gl_user.username).to eql uid + expect(gl_user.name).to eql 'John Doe' expect(gl_user.email).to eql 'johndoe@example.com' expect(gl_user.identities.length).to be 2 identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } } @@ -232,11 +234,13 @@ describe Gitlab::Auth::OAuth::User do ) end - it "has email set as synced" do + it "has name and email set as synced" do + expect(gl_user.user_synced_attributes_metadata.name_synced).to be_truthy expect(gl_user.user_synced_attributes_metadata.email_synced).to be_truthy end - it "has email set as read-only" do + it "has name and email set as read-only" do + expect(gl_user.read_only_attribute?(:name)).to be_truthy expect(gl_user.read_only_attribute?(:email)).to be_truthy end @@ -246,7 +250,7 @@ describe Gitlab::Auth::OAuth::User do end context "and LDAP user has an account already" do - let!(:existing_user) { create(:omniauth_user, email: 'john@example.com', extern_uid: dn, provider: 'ldapmain', username: 'john') } + let!(:existing_user) { create(:omniauth_user, name: 'John Doe', email: 'john@example.com', extern_uid: dn, provider: 'ldapmain', username: 'john') } it "adds the omniauth identity to the LDAP account" do allow(Gitlab::Auth::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) @@ -254,6 +258,7 @@ describe Gitlab::Auth::OAuth::User do expect(gl_user).to be_valid expect(gl_user.username).to eql 'john' + expect(gl_user.name).to eql 'John Doe' expect(gl_user.email).to eql 'john@example.com' expect(gl_user.identities.length).to be 2 identities_as_hash = gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } } diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 3fb41a626b2..4a4ac833e39 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -537,6 +537,18 @@ describe Gitlab::Git::Commit, :seed_helper do end end + describe '#gitaly_commit?' do + context 'when the commit data comes from gitaly' do + it { expect(commit.gitaly_commit?).to eq(true) } + end + + context 'when the commit data comes from a Hash' do + let(:commit) { described_class.new(repository, sample_commit_hash) } + + it { expect(commit.gitaly_commit?).to eq(false) } + end + end + describe '#has_zero_stats?' do it { expect(commit.has_zero_stats?).to eq(false) } end diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb index 37c3fae7cb7..2e4a7c36fb8 100644 --- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb @@ -11,6 +11,7 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi let(:source_commit) { project.repository.commit('feature') } let(:target_commit) { project.repository.commit('master') } let(:milestone) { create(:milestone, project: project) } + let(:state) { :closed } let(:pull_request) do alice = Gitlab::GithubImport::Representation::User.new(id: 4, login: 'alice') @@ -26,13 +27,13 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi source_repository_id: 400, target_repository_id: 200, source_repository_owner: 'alice', - state: :closed, + state: state, milestone_number: milestone.iid, author: alice, assignee: alice, created_at: created_at, updated_at: updated_at, - merged_at: merged_at + merged_at: state == :closed && merged_at ) end @@ -260,58 +261,63 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi end it 'does not create the source branch if merge request is merged' do - mr, exists = importer.create_merge_request - - importer.insert_git_data(mr, exists) + mr = insert_git_data expect(project.repository.branch_exists?(mr.source_branch)).to be_falsey expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy end - it 'creates the source branch if merge request is open' do - mr, exists = importer.create_merge_request - mr.state = 'opened' - mr.save + context 'when merge request is open' do + let(:state) { :opened } - # Ensure the project owner is creating the branches because the - # merge request author may not have access to push to this - # repository. - allow(project.repository).to receive(:add_branch).with(project.owner, anything, anything).and_call_original + it 'creates the source branch' do + # Ensure the project creator is creating the branches because the + # merge request author may not have access to push to this + # repository. The project owner may also be a group. + allow(project.repository).to receive(:add_branch).with(project.creator, anything, anything).and_call_original - importer.insert_git_data(mr, exists) + mr = insert_git_data - expect(project.repository.branch_exists?(mr.source_branch)).to be_truthy - expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy - end + expect(project.repository.branch_exists?(mr.source_branch)).to be_truthy + expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy + end - it 'ignores Git errors when creating a branch' do - mr, exists = importer.create_merge_request - mr.state = 'opened' - mr.save + it 'is able to retry on pre-receive errors' do + expect(importer).to receive(:insert_or_replace_git_data).twice.and_call_original + expect(project.repository).to receive(:add_branch).and_raise('exception') - expect(project.repository).to receive(:add_branch).and_raise(Gitlab::Git::CommandError) - expect(Gitlab::Sentry).to receive(:track_acceptable_exception).and_call_original + expect { insert_git_data }.to raise_error('exception') - importer.insert_git_data(mr, exists) + expect(project.repository).to receive(:add_branch).with(project.creator, anything, anything).and_call_original - expect(project.repository.branch_exists?(mr.source_branch)).to be_falsey - expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy + mr = insert_git_data + + expect(project.repository.branch_exists?(mr.source_branch)).to be_truthy + expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy + expect(mr.merge_request_diffs).to be_one + end + + it 'ignores Git command errors when creating a branch' do + expect(project.repository).to receive(:add_branch).and_raise(Gitlab::Git::CommandError) + expect(Gitlab::Sentry).to receive(:track_acceptable_exception).and_call_original + + mr = insert_git_data + + expect(project.repository.branch_exists?(mr.source_branch)).to be_falsey + expect(project.repository.branch_exists?(mr.target_branch)).to be_truthy + end end it 'creates the merge request diffs' do - mr, exists = importer.create_merge_request - - importer.insert_git_data(mr, exists) + mr = insert_git_data expect(mr.merge_request_diffs.exists?).to eq(true) end it 'creates the merge request diff commits' do - mr, exists = importer.create_merge_request - - importer.insert_git_data(mr, exists) + mr = insert_git_data - diff = mr.merge_request_diffs.take + diff = mr.merge_request_diffs.reload.first expect(diff.merge_request_diff_commits.exists?).to eq(true) end @@ -327,5 +333,11 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi expect(mr.merge_request_diffs.exists?).to eq(true) end end + + def insert_git_data + mr, exists = importer.create_merge_request + importer.insert_git_data(mr, exists) + mr + end end end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 4139d1c650c..d982053d92e 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::ReferenceExtractor do diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index cd9e4d48cd1..549cc5ac057 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -13,6 +13,8 @@ describe Gitlab::UsageData do create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true) create(:service, project: projects[1], type: 'SlackService', active: true) create(:service, project: projects[2], type: 'SlackService', active: true) + create(:project_error_tracking_setting, project: projects[0]) + create(:project_error_tracking_setting, project: projects[1], enabled: false) gcp_cluster = create(:cluster, :provided_by_gcp) create(:cluster, :provided_by_user) @@ -117,6 +119,7 @@ describe Gitlab::UsageData do projects_slack_slash_active projects_prometheus_active projects_with_repositories_enabled + projects_with_error_tracking_enabled pages_domains protected_branches releases @@ -146,6 +149,7 @@ describe Gitlab::UsageData do expect(count_data[:projects_slack_notifications_active]).to eq(2) expect(count_data[:projects_slack_slash_active]).to eq(1) expect(count_data[:projects_with_repositories_enabled]).to eq(2) + expect(count_data[:projects_with_error_tracking_enabled]).to eq(1) expect(count_data[:clusters_enabled]).to eq(7) expect(count_data[:project_clusters_enabled]).to eq(6) diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index 6972fc03415..3ce8aa1c7bc 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -22,7 +22,7 @@ describe Clusters::Applications::Runner do it 'should be initialized with 4 arguments' do expect(subject.name).to eq('runner') expect(subject.chart).to eq('runner/gitlab-runner') - expect(subject.version).to eq('0.2.0') + expect(subject.version).to eq('0.3.0') expect(subject).to be_rbac expect(subject.repository).to eq('https://charts.gitlab.io') expect(subject.files).to eq(gitlab_runner.files) @@ -40,7 +40,7 @@ describe Clusters::Applications::Runner do let(:gitlab_runner) { create(:clusters_applications_runner, :errored, runner: ci_runner, version: '0.1.13') } it 'should be initialized with the locked version' do - expect(subject.version).to eq('0.2.0') + expect(subject.version).to eq('0.3.0') end end end @@ -64,24 +64,45 @@ describe Clusters::Applications::Runner do end context 'without a runner' do - let(:project) { create(:project) } - let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) } let(:application) { create(:clusters_applications_runner, runner: nil, cluster: cluster) } + let(:runner) { application.runner } - it 'creates a runner' do - expect do - subject - end.to change { Ci::Runner.count }.by(1) + shared_examples 'runner creation' do + it 'creates a runner' do + expect { subject }.to change { Ci::Runner.count }.by(1) + end + + it 'uses the new runner token' do + expect(values).to match(/runnerToken: '?#{runner.token}/) + end end - it 'uses the new runner token' do - expect(values).to match(/runnerToken: '?#{application.reload.runner.token}/) + context 'project cluster' do + let(:project) { create(:project) } + let(:cluster) { create(:cluster, :with_installed_helm, projects: [project]) } + + include_examples 'runner creation' + + it 'creates a project runner' do + subject + + expect(runner).to be_project_type + expect(runner.projects).to eq [project] + end end - it 'assigns the new runner to runner' do - subject + context 'group cluster' do + let(:group) { create(:group) } + let(:cluster) { create(:cluster, :with_installed_helm, cluster_type: :group_type, groups: [group]) } + + include_examples 'runner creation' + + it 'creates a group runner' do + subject - expect(application.reload.runner).to be_project_type + expect(runner).to be_group_type + expect(runner.groups).to eq [group] + end end end diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb index 0f5d03ff458..30c504ebea8 100644 --- a/spec/models/commit_collection_spec.rb +++ b/spec/models/commit_collection_spec.rb @@ -37,12 +37,92 @@ describe CommitCollection do describe '#without_merge_commits' do it 'returns all commits except merge commits' do + merge_commit = project.commit("60ecb67744cb56576c30214ff52294f8ce2def98") + expect(merge_commit).to receive(:merge_commit?).and_return(true) + collection = described_class.new(project, [ - build(:commit), - build(:commit, :merge_commit) + commit, + merge_commit ]) - expect(collection.without_merge_commits.size).to eq(1) + expect(collection.without_merge_commits).to contain_exactly(commit) + end + end + + describe 'enrichment methods' do + let(:gitaly_commit) { commit } + let(:hash_commit) { Commit.from_hash(gitaly_commit.to_hash, project) } + + describe '#unenriched' do + it 'returns all commits that are not backed by gitaly data' do + collection = described_class.new(project, [gitaly_commit, hash_commit]) + + expect(collection.unenriched).to contain_exactly(hash_commit) + end + end + + describe '#fully_enriched?' do + it 'returns true when all commits are backed by gitaly data' do + collection = described_class.new(project, [gitaly_commit, gitaly_commit]) + + expect(collection.fully_enriched?).to eq(true) + end + + it 'returns false when any commits are not backed by gitaly data' do + collection = described_class.new(project, [gitaly_commit, hash_commit]) + + expect(collection.fully_enriched?).to eq(false) + end + + it 'returns true when the collection is empty' do + collection = described_class.new(project, []) + + expect(collection.fully_enriched?).to eq(true) + end + end + + describe '#enrich!' do + it 'replaces commits in the collection with those backed by gitaly data' do + collection = described_class.new(project, [hash_commit]) + + collection.enrich! + + new_commit = collection.commits.first + expect(new_commit.id).to eq(hash_commit.id) + expect(hash_commit.gitaly_commit?).to eq(false) + expect(new_commit.gitaly_commit?).to eq(true) + end + + it 'maintains the original order of the commits' do + gitaly_commits = [gitaly_commit] * 3 + hash_commits = [hash_commit] * 3 + # Interleave the gitaly and hash commits together + original_commits = gitaly_commits.zip(hash_commits).flatten + collection = described_class.new(project, original_commits) + + collection.enrich! + + original_commits.each_with_index do |original_commit, i| + new_commit = collection.commits[i] + expect(original_commit.id).to eq(new_commit.id) + end + end + + it 'fetches data if there are unenriched commits' do + collection = described_class.new(project, [hash_commit]) + + expect(Commit).to receive(:lazy).exactly(:once) + + collection.enrich! + end + + it 'does not fetch data if all commits are enriched' do + collection = described_class.new(project, [gitaly_commit]) + + expect(Commit).not_to receive(:lazy) + + collection.enrich! + end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 22998bc5b6a..2bcc8a77224 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -84,32 +84,27 @@ describe MergeRequest do describe '#default_squash_commit_message' do let(:project) { subject.project } - - def commit_collection(commit_hashes) - raw_commits = commit_hashes.map { |raw| Commit.from_hash(raw, project) } - - CommitCollection.new(project, raw_commits) - end + let(:is_multiline) { -> (c) { c.description.present? } } + let(:multiline_commits) { subject.commits.select(&is_multiline) } + let(:singleline_commits) { subject.commits.reject(&is_multiline) } it 'returns the oldest multiline commit message' do - commits = commit_collection([ - { message: 'Singleline', parent_ids: [] }, - { message: "Second multiline\nCommit message", parent_ids: [] }, - { message: "First multiline\nCommit message", parent_ids: [] } - ]) - - expect(subject).to receive(:commits).and_return(commits) - - expect(subject.default_squash_commit_message).to eq("First multiline\nCommit message") + expect(subject.default_squash_commit_message).to eq(multiline_commits.last.message) end it 'returns the merge request title if there are no multiline commits' do - commits = commit_collection([ - { message: 'Singleline', parent_ids: [] } - ]) + expect(subject).to receive(:commits).and_return( + CommitCollection.new(project, singleline_commits) + ) + + expect(subject.default_squash_commit_message).to eq(subject.title) + end - expect(subject).to receive(:commits).and_return(commits) + it 'does not return commit messages from multiline merge commits' do + collection = CommitCollection.new(project, multiline_commits).enrich! + expect(collection.commits).to all( receive(:merge_commit?).and_return(true) ) + expect(subject).to receive(:commits).and_return(collection) expect(subject.default_squash_commit_message).to eq(subject.title) end end @@ -1045,7 +1040,7 @@ describe MergeRequest do describe '#commit_authors' do it 'returns all the authors of every commit in the merge request' do - users = subject.commits.map(&:author_email).uniq.map do |email| + users = subject.commits.without_merge_commits.map(&:author_email).uniq.map do |email| create(:user, email: email) end @@ -1059,7 +1054,7 @@ describe MergeRequest do describe '#authors' do it 'returns a list with all the commit authors in the merge request and author' do - users = subject.commits.map(&:author_email).uniq.map do |email| + users = subject.commits.without_merge_commits.map(&:author_email).uniq.map do |email| create(:user, email: email) end diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index fd03f594c35..4a0f91c4c7a 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe MergeRequestPresenter do - let(:resource) { create :merge_request, source_project: project } - let(:project) { create :project } + let(:resource) { create(:merge_request, source_project: project) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '#ci_status' do @@ -523,4 +523,46 @@ describe MergeRequestPresenter do end end end + + describe '#can_push_to_source_branch' do + before do + allow(resource).to receive(:source_branch_exists?) { source_branch_exists } + + allow_any_instance_of(Gitlab::UserAccess::RequestCacheExtension) + .to receive(:can_push_to_branch?) + .with(resource.source_branch) + .and_return(can_push_to_branch) + end + + subject do + described_class.new(resource, current_user: user).can_push_to_source_branch? + end + + context 'when source branch exists AND user can push to source branch' do + let(:source_branch_exists) { true } + let(:can_push_to_branch) { true } + + it 'returns true' do + is_expected.to eq(true) + end + end + + context 'when source branch does not exists' do + let(:source_branch_exists) { false } + let(:can_push_to_branch) { true } + + it 'returns false' do + is_expected.to eq(false) + end + end + + context 'when user cannot push to source branch' do + let(:source_branch_exists) { true } + let(:can_push_to_branch) { false } + + it 'returns false' do + is_expected.to eq(false) + end + end + end end diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb index deb6abbc026..74820d39102 100644 --- a/spec/requests/api/graphql/project/merge_request_spec.rb +++ b/spec/requests/api/graphql/project/merge_request_spec.rb @@ -70,13 +70,13 @@ describe 'getting merge request information nested in a project' do context 'when there are pipelines' do before do - pipeline = create( + create( :ci_pipeline, project: merge_request.source_project, ref: merge_request.source_branch, sha: merge_request.diff_head_sha ) - merge_request.update!(head_pipeline: pipeline) + merge_request.update_head_pipeline end it 'has a head pipeline' do diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb index 4dbd79f2fc0..727fd8951f2 100644 --- a/spec/serializers/merge_request_widget_entity_spec.rb +++ b/spec/serializers/merge_request_widget_entity_spec.rb @@ -279,13 +279,18 @@ describe MergeRequestWidgetEntity do end describe 'commits_without_merge_commits' do + def find_matching_commit(short_id) + resource.commits.find { |c| c.short_id == short_id } + end + it 'should not include merge commits' do - # Mock all but the first 5 commits to be merge commits - resource.commits.each_with_index do |commit, i| - expect(commit).to receive(:merge_commit?).at_least(:once).and_return(i > 4) - end + commits_in_widget = subject[:commits_without_merge_commits] - expect(subject[:commits_without_merge_commits].size).to eq(5) + expect(commits_in_widget.length).to be < resource.commits.length + expect(commits_in_widget.length).to eq(resource.commits.without_merge_commits.length) + commits_in_widget.each do |c| + expect(find_matching_commit(c[:short_id]).merge_commit?).to eq(false) + end end end end diff --git a/spec/services/ci/destroy_pipeline_service_spec.rb b/spec/services/ci/destroy_pipeline_service_spec.rb index d896f990470..bff2b3179fb 100644 --- a/spec/services/ci/destroy_pipeline_service_spec.rb +++ b/spec/services/ci/destroy_pipeline_service_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe ::Ci::DestroyPipelineService do - let(:project) { create(:project) } - let!(:pipeline) { create(:ci_pipeline, project: project) } + let(:project) { create(:project, :repository) } + let!(:pipeline) { create(:ci_pipeline, :success, project: project, sha: project.commit.id) } subject { described_class.new(project, user).execute(pipeline) } @@ -17,6 +17,17 @@ describe ::Ci::DestroyPipelineService do expect { pipeline.reload }.to raise_error(ActiveRecord::RecordNotFound) end + it 'clears the cache', :use_clean_rails_memory_store_caching do + create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref) + + expect(project.pipeline_status.has_status?).to be_truthy + + subject + + # Need to use find to avoid memoization + expect(Project.find(project.id).pipeline_status.has_status?).to be_falsey + end + it 'does not log an audit event' do expect { subject }.not_to change { SecurityEvent.count } end diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb index cbdef008b07..20555873503 100644 --- a/spec/services/clusters/applications/create_service_spec.rb +++ b/spec/services/clusters/applications/create_service_spec.rb @@ -150,7 +150,7 @@ describe Clusters::Applications::CreateService do where(:application, :association, :allowed, :pre_create_helm) do 'helm' | :application_helm | true | false 'ingress' | :application_ingress | true | true - 'runner' | :application_runner | false | true + 'runner' | :application_runner | true | true 'jupyter' | :application_jupyter | false | true 'prometheus' | :application_prometheus | false | true end diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git/branch_push_service_spec.rb index e8fce951155..d0e2169b4a6 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git/branch_push_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GitPushService, services: true do +describe Git::BranchPushService, services: true do include RepoHelpers set(:user) { create(:user) } diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git/tag_push_service_spec.rb index 2699f6e7bcd..e151db5827f 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git/tag_push_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GitTagPushService do +describe Git::TagPushService do include RepoHelpers include GitHelpers diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb index dd5b8708f36..28663ca8853 100644 --- a/spec/services/releases/destroy_service_spec.rb +++ b/spec/services/releases/destroy_service_spec.rb @@ -28,13 +28,11 @@ describe Releases::DestroyService do end end - context 'when tag is not found' do + context 'when tag does not exist in the repository' do let(:tag) { 'v1.1.1' } - it 'returns an error' do - is_expected.to include(status: :error, - message: 'Tag does not exist', - http_status: 404) + it 'removes the orphaned release' do + expect { subject }.to change { project.releases.count }.by(-1) end end diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb index 7c8c1dd0d3a..a541d300595 100644 --- a/spec/services/tags/destroy_service_spec.rb +++ b/spec/services/tags/destroy_service_spec.rb @@ -7,11 +7,27 @@ describe Tags::DestroyService do let(:service) { described_class.new(project, user) } describe '#execute' do + subject { service.execute(tag_name) } + it 'removes the tag' do expect(repository).to receive(:before_remove_tag) expect(service).to receive(:success) service.execute('v1.1.0') end + + context 'when there is an associated release on the tag' do + let(:tag) { repository.tags.first } + let(:tag_name) { tag.name } + + before do + project.add_maintainer(user) + create(:release, tag: tag_name, project: project) + end + + it 'destroys the release' do + expect { subject }.to change { project.releases.count }.by(-1) + end + end end end diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index ecefdc23811..33648292037 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -23,7 +23,7 @@ module CycleAnalyticsHelpers return if skip_push_handler - GitPushService.new(project, + Git::BranchPushService.new(project, user, oldrev: oldrev, newrev: commit_shas.last, diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb index cceb179d53e..9cae8f934db 100644 --- a/spec/support/helpers/javascript_fixtures_helpers.rb +++ b/spec/support/helpers/javascript_fixtures_helpers.rb @@ -24,7 +24,7 @@ module JavaScriptFixturesHelpers # def clean_frontend_fixtures(directory_name) full_directory_name = File.expand_path(directory_name, fixture_root_path) - Dir[File.expand_path('*.html.raw', full_directory_name)].each do |file_name| + Dir[File.expand_path('*.html', full_directory_name)].each do |file_name| FileUtils.rm(file_name) end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index caae46a3175..9cddad71a51 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -33,8 +33,8 @@ describe PostReceive do describe "#process_project_changes" do context 'empty changes' do it "does not call any PushService but runs after project hooks" do - expect(GitPushService).not_to receive(:new) - expect(GitTagPushService).not_to receive(:new) + expect(Git::BranchPushService).not_to receive(:new) + expect(Git::TagPushService).not_to receive(:new) expect_next_instance_of(SystemHooksService) { |service| expect(service).to receive(:execute_hooks) } described_class.new.perform(gl_repository, key_id, "") @@ -45,8 +45,8 @@ describe PostReceive do let!(:key_id) { "" } it 'returns false' do - expect(GitPushService).not_to receive(:new) - expect(GitTagPushService).not_to receive(:new) + expect(Git::BranchPushService).not_to receive(:new) + expect(Git::TagPushService).not_to receive(:new) expect(described_class.new.perform(gl_repository, key_id, base64_changes)).to be false end @@ -60,9 +60,9 @@ describe PostReceive do context "branches" do let(:changes) { "123456 789012 refs/heads/tést" } - it "calls GitPushService" do - expect_any_instance_of(GitPushService).to receive(:execute).and_return(true) - expect_any_instance_of(GitTagPushService).not_to receive(:execute) + it "calls Git::BranchPushService" do + expect_any_instance_of(Git::BranchPushService).to receive(:execute).and_return(true) + expect_any_instance_of(Git::TagPushService).not_to receive(:execute) described_class.new.perform(gl_repository, key_id, base64_changes) end end @@ -70,9 +70,9 @@ describe PostReceive do context "tags" do let(:changes) { "123456 789012 refs/tags/tag" } - it "calls GitTagPushService" do - expect_any_instance_of(GitPushService).not_to receive(:execute) - expect_any_instance_of(GitTagPushService).to receive(:execute).and_return(true) + it "calls Git::TagPushService" do + expect_any_instance_of(Git::BranchPushService).not_to receive(:execute) + expect_any_instance_of(Git::TagPushService).to receive(:execute).and_return(true) described_class.new.perform(gl_repository, key_id, base64_changes) end end @@ -81,8 +81,8 @@ describe PostReceive do let(:changes) { "123456 789012 refs/merge-requests/123" } it "does not call any of the services" do - expect_any_instance_of(GitPushService).not_to receive(:execute) - expect_any_instance_of(GitTagPushService).not_to receive(:execute) + expect_any_instance_of(Git::BranchPushService).not_to receive(:execute) + expect_any_instance_of(Git::TagPushService).not_to receive(:execute) described_class.new.perform(gl_repository, key_id, base64_changes) end end @@ -125,7 +125,7 @@ describe PostReceive do allow_any_instance_of(Gitlab::DataBuilder::Repository).to receive(:update).and_return(fake_hook_data) # silence hooks so we can isolate allow_any_instance_of(Key).to receive(:post_create_hook).and_return(true) - allow_any_instance_of(GitPushService).to receive(:execute).and_return(true) + allow_any_instance_of(Git::BranchPushService).to receive(:execute).and_return(true) end it 'calls SystemHooksService' do diff --git a/yarn.lock b/yarn.lock index 15107a64991..4a7443c0bd8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -663,10 +663,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.54.0.tgz#00320e845efd46716042cde0c348b990d4908daf" integrity sha512-DR17iy8TM5IbXEacqiDP0p8SuC/J8EL+98xbfVz5BKvRsPHpeZJQNlBF/petIV5d+KWM5A9v3GZTY7uMU7z/JQ== -"@gitlab/ui@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-2.3.0.tgz#7840aa4ad6638a90e82fa99f3a5dcac1785f7477" - integrity sha512-7hH+Q6SeP0hMMM21TQoGmvNjBcadgD+gWlGcKlnN1euH+6kfmOT5TCdrvsUjsZSNdycSXrEMMcQYy2oXG1sbdw== +"@gitlab/ui@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-3.0.0.tgz#33ca2808dbd4395e69a366a219d1edc1f3dbccd5" + integrity sha512-pDEa2k6ln5GE/N2z0V7dNEeFtSTW0p9ipO2/N9q6QMxO7fhhOhpMC0QVbdIljKTbglspDWI5v6BcqUjzYri5Pg== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "^2.0.0-rc.11" @@ -1356,6 +1356,11 @@ async-each@^1.0.0: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" integrity sha1-GdOGodntxufByF04iu28xW0zYC0= +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" @@ -1619,6 +1624,13 @@ blob@0.0.4: resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + bluebird@^3.1.1, bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@~3.5.0: version "3.5.3" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" @@ -1957,6 +1969,14 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw== +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + camelcase-keys@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" @@ -1966,6 +1986,16 @@ camelcase-keys@^4.0.0: map-obj "^2.0.0" quick-lru "^1.0.0" +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + camelcase@^4.0.0, camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" @@ -2010,7 +2040,7 @@ ccount@^1.0.0: resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.3.tgz#f1cec43f332e2ea5a569fd46f9f5bde4e6102aff" integrity sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw== -chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3: +chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= @@ -2060,7 +2090,7 @@ chardet@^0.5.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029" integrity sha512-9ZTaoBaePSCFvNlNGrsyI8ZVACP2svUtq0DkM7t4K2ClAa96sqOIRjAzDTc8zXzFt1cZR46rRzLTiHFSJ+Qw0g== -"charenc@>= 0.0.1": +"charenc@>= 0.0.1", charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= @@ -2204,6 +2234,15 @@ clipboard@^1.5.5, clipboard@^1.7.1: select "^1.1.2" tiny-emitter "^2.0.0" +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + cliui@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc" @@ -2572,6 +2611,14 @@ cropper@^2.3.0: dependencies: jquery ">= 1.9.1" +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2592,7 +2639,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -"crypt@>= 0.0.1": +"crypt@>= 0.0.1", crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= @@ -3029,7 +3076,7 @@ decamelize-keys@^1.0.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -4414,6 +4461,16 @@ fsevents@^1.2.2, fsevents@^1.2.3: nan "^2.9.2" node-pre-gyp "^0.10.0" +fstream@^1.0.0, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -4443,11 +4500,23 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U= +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -4512,7 +4581,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -"glob@5 - 7", glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: +"glob@5 - 7", glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -4629,6 +4698,15 @@ globjoin@^0.1.4: resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + gonzales-pe@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.3.tgz#41091703625433285e0aee3aa47829fc1fbeb6f2" @@ -5098,6 +5176,18 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + integrity sha1-4g/146KvwmkDILbcVSaCqcf631E= + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + indent-string@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" @@ -5121,7 +5211,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -5271,7 +5361,7 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" -is-buffer@^1.1.5: +is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -5364,6 +5454,13 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -5532,6 +5629,11 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + is-whitespace-character@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.2.tgz#ede53b4c6f6fb3874533751ec9280d01928d03ed" @@ -6090,6 +6192,11 @@ jquery.waitforimages@^2.2.0: resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== +js-base64@^2.1.8: + version "2.5.1" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121" + integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw== + js-beautify@^1.8.8: version "1.8.9" resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.8.9.tgz#08e3c05ead3ecfbd4f512c3895b1cda76c87d523" @@ -6493,6 +6600,17 @@ linkify-it@^2.0.0: dependencies: uc.micro "^1.0.1" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" @@ -6543,12 +6661,17 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= + lodash.camelcase@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.clonedeep@^4.5.0: +lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= @@ -6603,7 +6726,7 @@ lodash.upperfirst@4.3.1: resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984= -lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0: +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.10: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== @@ -6720,7 +6843,7 @@ map-cache@^0.2.2: resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0: +map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= @@ -6776,6 +6899,15 @@ md5.js@^1.3.4: hash-base "^3.0.0" inherits "^2.0.1" +md5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" + integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk= + dependencies: + charenc "~0.0.1" + crypt "~0.0.1" + is-buffer "~1.1.1" + mdast-util-compact@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.2.tgz#c12ebe16fffc84573d3e19767726de226e95f649" @@ -6822,6 +6954,22 @@ memory-fs@^0.4.0, memory-fs@~0.4.1: errno "^0.1.3" readable-stream "^2.0.1" +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + meow@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" @@ -6954,7 +7102,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -6979,7 +7127,7 @@ minimist@1.1.x: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= -minimist@1.2.0, minimist@^1.1.1, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= @@ -7023,7 +7171,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.x, mkdirp@0.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.x, mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -7092,10 +7240,10 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== +nan@^2.10.0, nan@^2.9.2: + version "2.13.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.1.tgz#a15bee3790bde247e8f38f1d446edcdaeb05f2dd" + integrity sha512-I6YB/YEuDeUZMmhscXKxGgZlFnhsn5y0hgOZBadkzfTRrZBtJDZeg6eQf7PYMIEclwmorTKK8GztsyOUSVBREA== nanomatch@^1.2.9: version "1.2.9" @@ -7157,6 +7305,24 @@ node-forge@0.6.33: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.6.33.tgz#463811879f573d45155ad6a9f43dc296e8e85ebc" integrity sha1-RjgRh59XPUUVWtap9D3ClujoXrw= +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -7229,6 +7395,31 @@ node-releases@^1.1.3: dependencies: semver "^5.3.0" +node-sass@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a" + integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA== + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.10.0" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + nodemon@^1.18.9: version "1.18.9" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.9.tgz#90b467efd3b3c81b9453380aeb2a2cba535d0ead" @@ -7245,7 +7436,7 @@ nodemon@^1.18.9: undefsafe "^2.0.2" update-notifier "^2.5.0" -nopt@3.x: +"nopt@2 || 3", nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= @@ -7328,7 +7519,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -7541,6 +7732,13 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + os-locale@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" @@ -7564,7 +7762,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4: +osenv@0, osenv@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -7802,6 +8000,15 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -8463,6 +8670,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" @@ -8487,6 +8702,15 @@ read-pkg-up@^4.0.0: find-up "^3.0.0" read-pkg "^3.0.0" +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" @@ -8556,6 +8780,14 @@ realpath-native@^1.0.0, realpath-native@^1.0.2: dependencies: util.promisify "^1.0.0" +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + redent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" @@ -8745,6 +8977,13 @@ repeat-string@^1.5.4, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + replace-ext@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" @@ -8766,7 +9005,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.0" tough-cookie ">=2.3.3" -request@^2.87.0: +request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -8894,7 +9133,7 @@ rfdc@^1.1.2: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349" integrity sha512-92ktAgvZhBzYTIK0Mja9uen5q5J3NRVMoDkJL2VMwq6SXjVCgqvQeVP2XAaUY6HT+XpQYeLSjb3UoitBryKmdA== -rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -9002,6 +9241,16 @@ sanitize-html@^1.16.1: srcset "^1.0.0" xtend "^4.0.0" +sass-graph@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k= + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -9033,6 +9282,14 @@ scope-css@^1.0.5: slugify "^1.3.1" strip-css-comments "^3.0.0" +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -9067,6 +9324,11 @@ semver-diff@^2.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -9384,6 +9646,13 @@ source-map@0.5.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86" integrity sha1-D+llA6yGpa213mP05BKuSHLNvoY= +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -9521,6 +9790,13 @@ statuses@~1.3.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -9655,6 +9931,13 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -9672,6 +9955,13 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + strip-indent@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" @@ -9705,10 +9995,10 @@ stylelint-error-string-formatter@^1.0.1: resolved "https://registry.yarnpkg.com/stylelint-error-string-formatter/-/stylelint-error-string-formatter-1.0.1.tgz#366387825d6fb59569e8c5c3f5682398733756f9" integrity sha512-8zy0UsdnQZKVDwjWMQX36b30TaNMGcM2FzBcK9cshpXerpJ3AvF2/zw7FJ3Efm6DFviTBVsxR14F3FnDFhCxJw== -stylelint-scss@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.5.3.tgz#e158b3061eeec26d7f6088f346998a797432f3c8" - integrity sha512-QESQUOY1ldU5tlJTTM3Megz/QtJ39S58ByjZ7dZobGDq9qMjy5jbC7PDUasrv/T7pB1UbpPojpxX9K1OR7IPEg== +stylelint-scss@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.5.4.tgz#ff3ee989ac48f5c4f57313523b5ace059ffd6cc2" + integrity sha512-hEdEOfFXVqxWcUbenBONW/cAw5cJcEDasY8tGwKNAAn1GDHoZO1ATdWpr+iIk325mPGIQqVb1sUxsRxuL70trw== dependencies: lodash "^4.17.11" postcss-media-query-parser "^0.2.3" @@ -9847,6 +10137,15 @@ tapable@^1.0.0, tapable@^1.1.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.0.tgz#0d076a172e3d9ba088fd2272b2668fb8d194b78c" integrity sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA== +tar@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + tar@^4: version "4.4.4" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" @@ -10107,6 +10406,11 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + trim-newlines@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" @@ -10132,6 +10436,13 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.3.tgz#e29bd1614c6458d44869fc28b255ab7857ef7c24" integrity sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw== +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + tryer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7" @@ -10910,12 +11221,17 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.1.1, which@^1.2.1, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@1, which@^1.1.1, which@^1.2.1, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -11111,6 +11427,13 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= + dependencies: + camelcase "^3.0.0" + yargs-parser@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" @@ -11172,6 +11495,25 @@ yargs@^12.0.2, yargs@^12.0.4: y18n "^3.2.1 || ^4.0.0" yargs-parser "^11.1.1" +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + yarn-deduplicate@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/yarn-deduplicate/-/yarn-deduplicate-1.1.1.tgz#19b4a87654b66f55bf3a4bd6b153b4e4ab1b6e6d" |