diff options
-rw-r--r-- | .gitlab/ci/frontend.gitlab-ci.yml | 1 | ||||
-rw-r--r-- | .gitlab/ci/review.gitlab-ci.yml | 4 | ||||
-rw-r--r-- | app/assets/javascripts/notes/components/discussion_actions.vue | 58 | ||||
-rw-r--r-- | app/assets/javascripts/notes/components/noteable_discussion.vue | 46 | ||||
-rw-r--r-- | app/assets/stylesheets/components/dashboard_skeleton.scss | 15 | ||||
-rw-r--r-- | changelogs/unreleased/58293-extract-discussion-actions.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/rename_auto_deploy_app_links.yml | 5 | ||||
-rw-r--r-- | doc/ci/merge_request_pipelines/index.md | 2 | ||||
-rw-r--r-- | doc/topics/autodevops/index.md | 8 | ||||
-rw-r--r-- | doc/user/project/clusters/serverless/index.md | 15 | ||||
-rw-r--r-- | qa/qa/page/component/note.rb | 2 | ||||
-rw-r--r-- | spec/frontend/notes/components/discussion_actions_spec.js | 104 |
12 files changed, 201 insertions, 64 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 5acfdb4e832..fd179f77e26 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -104,6 +104,7 @@ gitlab:ui:visual: artifacts: paths: - tests/__image_snapshots__/ + when: always karma: extends: .dedicated-no-docs-pull-cache-job diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml index a7f6caedd37..dee72930a28 100644 --- a/.gitlab/ci/review.gitlab-ci.yml +++ b/.gitlab/ci/review.gitlab-ci.yml @@ -83,7 +83,6 @@ schedule:review-build-cng: <<: *review-schedules-only <<: *review-build-cng-base - .review-deploy-base: &review-deploy-base <<: *review-base allow_failure: true @@ -145,6 +144,7 @@ schedule:review-deploy: review-qa-smoke: <<: *review-qa-base + retry: 2 script: - wait_for_job_to_be_done "review-deploy" - gitlab-qa Test::Instance::Smoke "${QA_IMAGE}" "${CI_ENVIRONMENT_URL}" @@ -175,6 +175,7 @@ review-performance: <<: *review-performance-base review-stop: + <<: *review-base extends: .single-script-job-dedicated-runner image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-charts-build-base allow_failure: true @@ -229,4 +230,3 @@ danger-review: - node --version - yarn install --frozen-lockfile --cache-folder .yarn-cache - danger --fail-on-errors=true - diff --git a/app/assets/javascripts/notes/components/discussion_actions.vue b/app/assets/javascripts/notes/components/discussion_actions.vue new file mode 100644 index 00000000000..22cca756ef6 --- /dev/null +++ b/app/assets/javascripts/notes/components/discussion_actions.vue @@ -0,0 +1,58 @@ +<script> +import ReplyPlaceholder from './discussion_reply_placeholder.vue'; +import ResolveDiscussionButton from './discussion_resolve_button.vue'; +import ResolveWithIssueButton from './discussion_resolve_with_issue_button.vue'; +import JumpToNextDiscussionButton from './discussion_jump_to_next_button.vue'; + +export default { + name: 'DiscussionActions', + components: { + ReplyPlaceholder, + ResolveDiscussionButton, + ResolveWithIssueButton, + JumpToNextDiscussionButton, + }, + props: { + discussion: { + type: Object, + required: true, + }, + isResolving: { + type: Boolean, + required: true, + }, + resolveButtonTitle: { + type: String, + required: true, + }, + resolveWithIssuePath: { + type: String, + required: false, + default: '', + }, + shouldShowJumpToNextDiscussion: { + type: Boolean, + required: true, + }, + }, +}; +</script> + +<template> + <div class="discussion-with-resolve-btn"> + <reply-placeholder class="qa-discussion-reply" @onClick="$emit('showReplyForm')" /> + <resolve-discussion-button + v-if="discussion.resolvable" + :is-resolving="isResolving" + :button-title="resolveButtonTitle" + @onClick="$emit('resolve')" + /> + <div v-if="discussion.resolvable" class="btn-group discussion-actions ml-sm-2" role="group"> + <resolve-with-issue-button v-if="resolveWithIssuePath" :url="resolveWithIssuePath" /> + <jump-to-next-discussion-button + v-if="shouldShowJumpToNextDiscussion" + @onClick="$emit('jumpToNextDiscussion')" + /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index a3d664a738f..89563711bcd 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -14,7 +14,6 @@ import { SYSTEM_NOTE } from '../constants'; import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; import noteableNote from './noteable_note.vue'; import noteHeader from './note_header.vue'; -import resolveDiscussionButton from './discussion_resolve_button.vue'; import toggleRepliesWidget from './toggle_replies_widget.vue'; import noteSignedOutWidget from './note_signed_out_widget.vue'; import noteEditedText from './note_edited_text.vue'; @@ -25,10 +24,8 @@ import placeholderSystemNote from '../../vue_shared/components/notes/placeholder import noteable from '../mixins/noteable'; import resolvable from '../mixins/resolvable'; import discussionNavigation from '../mixins/discussion_navigation'; -import ReplyPlaceholder from './discussion_reply_placeholder.vue'; -import ResolveWithIssueButton from './discussion_resolve_with_issue_button.vue'; -import jumpToNextDiscussionButton from './discussion_jump_to_next_button.vue'; import eventHub from '../event_hub'; +import DiscussionActions from './discussion_actions.vue'; export default { name: 'NoteableDiscussion', @@ -40,16 +37,13 @@ export default { noteSignedOutWidget, noteEditedText, noteForm, - resolveDiscussionButton, - jumpToNextDiscussionButton, toggleRepliesWidget, - ReplyPlaceholder, placeholderNote, placeholderSystemNote, - ResolveWithIssueButton, systemNote, DraftNote: () => import('ee_component/batch_comments/components/draft_note.vue'), TimelineEntryItem, + DiscussionActions, }, directives: { GlTooltip: GlTooltipDirective, @@ -465,31 +459,17 @@ Please check your network connection and try again.`; :class="{ 'is-replying': isReplying }" class="discussion-reply-holder" > - <template v-if="!isReplying && canReply"> - <div class="discussion-with-resolve-btn"> - <reply-placeholder class="qa-discussion-reply" @onClick="showReplyForm" /> - <resolve-discussion-button - v-if="discussion.resolvable" - :is-resolving="isResolving" - :button-title="resolveButtonTitle" - @onClick="resolveHandler" - /> - <div - v-if="discussion.resolvable" - class="btn-group discussion-actions ml-sm-2" - role="group" - > - <resolve-with-issue-button - v-if="resolveWithIssuePath" - :url="resolveWithIssuePath" - /> - <jump-to-next-discussion-button - v-if="shouldShowJumpToNextDiscussion" - @onClick="jumpToNextDiscussion" - /> - </div> - </div> - </template> + <discussion-actions + v-if="!isReplying && canReply" + :discussion="discussion" + :is-resolving="isResolving" + :resolve-button-title="resolveButtonTitle" + :resolve-with-issue-path="resolveWithIssuePath" + :should-show-jump-to-next-discussion="shouldShowJumpToNextDiscussion" + @showReplyForm="showReplyForm" + @resolve="resolveHandler" + @jumpToNextDiscussion="jumpToNextDiscussion" + /> <note-form v-if="isReplying" ref="noteForm" diff --git a/app/assets/stylesheets/components/dashboard_skeleton.scss b/app/assets/stylesheets/components/dashboard_skeleton.scss index 42ede599bc6..9775c329922 100644 --- a/app/assets/stylesheets/components/dashboard_skeleton.scss +++ b/app/assets/stylesheets/components/dashboard_skeleton.scss @@ -8,10 +8,6 @@ &-warning { background-color: $orange-100; } - - &-failed { - background-color: $red-100; - } } &-body { @@ -36,10 +32,6 @@ border-radius: $gl-padding; height: $gl-padding-32; - &-failed { - background-color: $red-100; - } - &-arrow { color: $gray-300; } @@ -56,6 +48,13 @@ } } + &-header, + &-footer { + &-failed { + background-color: $red-100; + } + } + &-skeleton-info { border-radius: $gl-padding; height: $gl-padding; diff --git a/changelogs/unreleased/58293-extract-discussion-actions.yml b/changelogs/unreleased/58293-extract-discussion-actions.yml new file mode 100644 index 00000000000..2ca4716a6de --- /dev/null +++ b/changelogs/unreleased/58293-extract-discussion-actions.yml @@ -0,0 +1,5 @@ +--- +title: Extract DiscussionActions component from NoteableDiscussion +merge_request: 27227 +author: +type: other diff --git a/changelogs/unreleased/rename_auto_deploy_app_links.yml b/changelogs/unreleased/rename_auto_deploy_app_links.yml new file mode 100644 index 00000000000..c56b5fb5e5c --- /dev/null +++ b/changelogs/unreleased/rename_auto_deploy_app_links.yml @@ -0,0 +1,5 @@ +--- +title: Move location of charts/auto-deploy-app -> gitlab-org/charts/auto-deploy-app +merge_request: 27477 +author: +type: changed diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md index 2de751c9e62..6a03ab910fc 100644 --- a/doc/ci/merge_request_pipelines/index.md +++ b/doc/ci/merge_request_pipelines/index.md @@ -69,7 +69,7 @@ when a merge request was created or updated. For example: ## Combined ref pipelines **[PREMIUM]** -> [GitLab Premium](https://about.gitlab.com/pricing/) 11.10. +> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7380) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10. It's possible for your source and target branches to diverge, which can result in the scenario that source branch's pipeline was green, the target's pipeline was green, diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 1d517a65ce2..0ab9406c681 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -460,7 +460,7 @@ for example after the merge request is merged, the Review App will automatically be deleted. Review apps are deployed using the -[auto-deploy-app](https://gitlab.com/charts/auto-deploy-app) chart with +[auto-deploy-app](https://gitlab.com/gitlab-org/charts/auto-deploy-app) chart with Helm. The app will be deployed into the [Kubernetes namespace](../../user/project/clusters/index.md#deployment-variables) for the environment. @@ -528,7 +528,7 @@ You can make use of [environment variables](#environment-variables) to automatic scale your pod replicas. Apps are deployed using the -[auto-deploy-app](https://gitlab.com/charts/auto-deploy-app) chart with +[auto-deploy-app](https://gitlab.com/gitlab-org/charts/auto-deploy-app) chart with Helm. The app will be deployed into the [Kubernetes namespace](../../user/project/clusters/index.md#deployment-variables) for the environment. @@ -667,7 +667,7 @@ repo or by specifying a project variable: - **Bundled chart** - If your project has a `./chart` directory with a `Chart.yaml` file in it, Auto DevOps will detect the chart and use it instead of the [default - one](https://gitlab.com/charts/auto-deploy-app). + one](https://gitlab.com/gitlab-org/charts/auto-deploy-app). This can be a great way to control exactly how your application is deployed. - **Project variable** - Create a [project variable](../../ci/variables/README.md#gitlab-cicd-environment-variables) `AUTO_DEVOPS_CHART` with the URL of a custom chart to use or create two project variables `AUTO_DEVOPS_CHART_REPOSITORY` with the URL of a custom chart repository and `AUTO_DEVOPS_CHART` with the path to the chart. @@ -735,7 +735,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac | **Variable** | **Description** | | ------------ | --------------- | | `AUTO_DEVOPS_DOMAIN` | The [Auto DevOps domain](#auto-devops-base-domain). By default, set automatically by the [Auto DevOps setting](#enablingdisabling-auto-devops). This variable is deprecated and [is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959). Use `KUBE_INGRESS_BASE_DOMAIN` instead. | -| `AUTO_DEVOPS_CHART` | The Helm Chart used to deploy your apps; defaults to the one [provided by GitLab](https://gitlab.com/charts/auto-deploy-app). | +| `AUTO_DEVOPS_CHART` | The Helm Chart used to deploy your apps; defaults to the one [provided by GitLab](https://gitlab.com/gitlab-org/charts/auto-deploy-app). | | `AUTO_DEVOPS_CHART_REPOSITORY` | The Helm Chart repository used to search for charts; defaults to `https://charts.gitlab.io`. | | `REPLICAS` | The number of replicas to deploy; defaults to 1. | | `PRODUCTION_REPLICAS` | The number of replicas to deploy in the production environment. This takes precedence over `REPLICAS`; defaults to 1. | diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md index 5b7e9ef906f..dfbed0ec95f 100644 --- a/doc/user/project/clusters/serverless/index.md +++ b/doc/user/project/clusters/serverless/index.md @@ -158,21 +158,6 @@ Follow these steps to deploy a function using the Node.js runtime to your Knativ description: "node.js runtime function" environment: MY_FUNCTION: echo-js - - echo-rb: - handler: MyEcho.my_function - source: ./echo-rb - runtime: https://gitlab.com/gitlab-org/serverless/runtimes/ruby - description: "Ruby runtime function" - environment: - MY_FUNCTION: echo-rb - - echo-docker: - handler: echo-docker - source: ./echo-docker - description: "Dockerfile runtime function" - environment: - MY_FUNCTION: echo-docker ``` Explanation of the fields used above: diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb index f5add6bc9b5..07e191f1c9b 100644 --- a/qa/qa/page/component/note.rb +++ b/qa/qa/page/component/note.rb @@ -15,7 +15,7 @@ module QA element :reply_comment_button end - base.view 'app/assets/javascripts/notes/components/noteable_discussion.vue' do + base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do element :discussion_reply end diff --git a/spec/frontend/notes/components/discussion_actions_spec.js b/spec/frontend/notes/components/discussion_actions_spec.js new file mode 100644 index 00000000000..0a52c81571e --- /dev/null +++ b/spec/frontend/notes/components/discussion_actions_spec.js @@ -0,0 +1,104 @@ +import createStore from '~/notes/stores'; +import { shallowMount, mount, createLocalVue } from '@vue/test-utils'; +import { discussionMock } from '../../../javascripts/notes/mock_data'; +import DiscussionActions from '~/notes/components/discussion_actions.vue'; +import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue'; +import ResolveDiscussionButton from '~/notes/components/discussion_resolve_button.vue'; +import ResolveWithIssueButton from '~/notes/components/discussion_resolve_with_issue_button.vue'; +import JumpToNextDiscussionButton from '~/notes/components/discussion_jump_to_next_button.vue'; + +describe('DiscussionActions', () => { + let wrapper; + const createComponentFactory = (shallow = true) => props => { + const localVue = createLocalVue(); + const store = createStore(); + const mountFn = shallow ? shallowMount : mount; + + wrapper = mountFn(DiscussionActions, { + localVue, + store, + propsData: { + discussion: discussionMock, + isResolving: false, + resolveButtonTitle: 'Resolve discussion', + resolveWithIssuePath: '/some/issue/path', + shouldShowJumpToNextDiscussion: true, + ...props, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('rendering', () => { + const createComponent = createComponentFactory(); + + it('renders reply placeholder, resolve discussion button, resolve with issue button and jump to next discussion button', () => { + createComponent(); + expect(wrapper.find(ReplyPlaceholder).exists()).toBe(true); + expect(wrapper.find(ResolveDiscussionButton).exists()).toBe(true); + expect(wrapper.find(ResolveWithIssueButton).exists()).toBe(true); + expect(wrapper.find(JumpToNextDiscussionButton).exists()).toBe(true); + }); + + it('only renders reply placholder if disccusion is not resolvable', () => { + const discussion = { ...discussionMock }; + discussion.resolvable = false; + createComponent({ discussion }); + + expect(wrapper.find(ReplyPlaceholder).exists()).toBe(true); + expect(wrapper.find(ResolveDiscussionButton).exists()).toBe(false); + expect(wrapper.find(ResolveWithIssueButton).exists()).toBe(false); + expect(wrapper.find(JumpToNextDiscussionButton).exists()).toBe(false); + }); + + it('does not render resolve with issue button if resolveWithIssuePath is falsy', () => { + createComponent({ resolveWithIssuePath: '' }); + + expect(wrapper.find(ResolveWithIssueButton).exists()).toBe(false); + }); + + it('does not render jump to next discussion button if shouldShowJumpToNextDiscussion is false', () => { + createComponent({ shouldShowJumpToNextDiscussion: false }); + + expect(wrapper.find(JumpToNextDiscussionButton).exists()).toBe(false); + }); + }); + + describe('events handling', () => { + const createComponent = createComponentFactory(false); + + beforeEach(() => { + createComponent(); + }); + + it('emits showReplyForm event when clicking on reply placeholder', () => { + jest.spyOn(wrapper.vm, '$emit'); + wrapper + .find(ReplyPlaceholder) + .find('button') + .trigger('click'); + expect(wrapper.vm.$emit).toHaveBeenCalledWith('showReplyForm'); + }); + + it('emits resolve event when clicking on resolve button', () => { + jest.spyOn(wrapper.vm, '$emit'); + wrapper + .find(ResolveDiscussionButton) + .find('button') + .trigger('click'); + expect(wrapper.vm.$emit).toHaveBeenCalledWith('resolve'); + }); + + it('emits jumpToNextDiscussion event when clicking on jump to next discussion button', () => { + jest.spyOn(wrapper.vm, '$emit'); + wrapper + .find(JumpToNextDiscussionButton) + .find('button') + .trigger('click'); + expect(wrapper.vm.$emit).toHaveBeenCalledWith('jumpToNextDiscussion'); + }); + }); +}); |