diff options
50 files changed, 414 insertions, 213 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/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index c48672183b9..466c47b37c7 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -1,6 +1,6 @@ .dedicated-runner: retry: - max: 1 # This is confusing but this means "2 runs at max". + max: 2 # This is confusing but this means "3 runs at max". when: - unknown_failure - api_failure 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/due_date_select.js b/app/assets/javascripts/due_date_select.js index cb1b1173190..3c650397a19 100644 --- a/app/assets/javascripts/due_date_select.js +++ b/app/assets/javascripts/due_date_select.js @@ -104,7 +104,7 @@ class DueDateSelect { const dateObj = new Date(dateArray[0], dateArray[1] - 1, dateArray[2]); this.displayedDate = dateFormat(dateObj, 'mmm d, yyyy'); } else { - this.displayedDate = 'No due date'; + this.displayedDate = __('None'); } } @@ -132,7 +132,7 @@ class DueDateSelect { submitSelectedDate(isDropdown) { const selectedDateValue = this.datePayload[this.abilityName].due_date; - const hasDueDate = this.displayedDate !== 'No due date'; + const hasDueDate = this.displayedDate !== __('None'); const displayedDateStyle = hasDueDate ? 'bold' : 'no-value'; this.$loading.removeClass('hidden').fadeIn(); diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js index 2b4ddd7afbc..ed794779ff2 100644 --- a/app/assets/javascripts/monitoring/monitoring_bundle.js +++ b/app/assets/javascripts/monitoring/monitoring_bundle.js @@ -2,7 +2,7 @@ import Vue from 'vue'; import { parseBoolean } from '~/lib/utils/common_utils'; import Dashboard from './components/dashboard.vue'; -export default () => { +export default (props = {}) => { const el = document.getElementById('prometheus-graphs'); if (el && el.dataset) { @@ -15,6 +15,7 @@ export default () => { ...el.dataset, hasMetrics: parseBoolean(el.dataset.hasMetrics), showTimeWindowDropdown: gon.features.metricsTimeWindow, + ...props, }, }); }, 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/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index e82756e4643..edaf07063ec 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -12,6 +12,9 @@ class Clusters::ClustersController < Clusters::BaseController before_action :authorize_update_cluster!, only: [:update] before_action :authorize_admin_cluster!, only: [:destroy] before_action :update_applications_status, only: [:cluster_status] + before_action only: [:show] do + push_frontend_feature_flag(:metrics_time_window) + end helper_method :token_in_session diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb index 45955783be9..ce7d0b8699c 100644 --- a/app/finders/autocomplete/users_finder.rb +++ b/app/finders/autocomplete/users_finder.rb @@ -2,6 +2,8 @@ module Autocomplete class UsersFinder + include Gitlab::Utils::StrongMemoize + # The number of users to display in the results is hardcoded to 20, and # pagination is not supported. This ensures that performance remains # consistent and removes the need for implementing keyset pagination to @@ -31,7 +33,7 @@ module Autocomplete # Include current user if available to filter by "Me" items.unshift(current_user) if prepend_current_user? - if prepend_author? && (author = User.find_by_id(author_id)) + if prepend_author? && author&.active? items.unshift(author) end end @@ -41,6 +43,12 @@ module Autocomplete private + def author + strong_memoize(:author) do + User.find_by_id(author_id) + end + end + # Returns the users based on the input parameters, as an Array. # # This method is separate so it is easier to extend in EE. diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index f7e54833296..38cbc9ce8eb 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -3,7 +3,7 @@ module Clusters module Applications class Knative < ApplicationRecord - VERSION = '0.3.0'.freeze + VERSION = '0.5.0'.freeze REPOSITORY = 'https://storage.googleapis.com/triggermesh-charts'.freeze METRICS_CONFIG = 'https://storage.googleapis.com/triggermesh-charts/istio-metrics.yaml'.freeze FETCH_IP_ADDRESS_DELAY = 30.seconds diff --git a/app/services/clusters/refresh_service.rb b/app/services/clusters/refresh_service.rb index 7c82b98a33f..76ad8dd0fb0 100644 --- a/app/services/clusters/refresh_service.rb +++ b/app/services/clusters/refresh_service.rb @@ -21,7 +21,11 @@ module Clusters private_class_method :projects_with_missing_kubernetes_namespaces_for_cluster def self.clusters_with_missing_kubernetes_namespaces_for_project(project) - project.all_clusters.missing_kubernetes_namespace(project.kubernetes_namespaces) + if Feature.enabled?(:ci_preparing_state, default_enabled: true) + project.clusters.missing_kubernetes_namespace(project.kubernetes_namespaces) + else + project.all_clusters.missing_kubernetes_namespace(project.kubernetes_namespaces) + end end private_class_method :clusters_with_missing_kubernetes_namespaces_for_project diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index 2c95ac6dbb3..4bf1d8702af 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -77,7 +77,7 @@ = edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago') - #js-related-merge-requests{ data: { endpoint: api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: @issue.iid), project_namespace: @project.namespace.path, project_path: @project.path } } + #js-related-merge-requests{ data: { endpoint: expose_url(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: @issue.iid)), project_namespace: @project.namespace.path, project_path: @project.path } } - if can?(current_user, :download_code, @project) #related-branches{ data: { url: related_branches_project_issue_path(@project, @issue) } } diff --git a/app/views/shared/boards/components/sidebar/_due_date.html.haml b/app/views/shared/boards/components/sidebar/_due_date.html.haml index 5630375f428..117d56b30f5 100644 --- a/app/views/shared/boards/components/sidebar/_due_date.html.haml +++ b/app/views/shared/boards/components/sidebar/_due_date.html.haml @@ -7,7 +7,7 @@ .value .value-content %span.no-value{ "v-if" => "!issue.dueDate" } - = _("No due date") + = _("None") %span.bold{ "v-if" => "issue.dueDate" } {{ issue.dueDate | due-date }} - if can_admin_issue? diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 0798b1da4b7..d4be7289a49 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -73,7 +73,7 @@ %span.bold= issuable_sidebar[:due_date].to_s(:medium) - else %span.no-value - = _('No due date') + = _('None') - if can_edit_issuable %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable_sidebar[:due_date].nil?) } \- diff --git a/app/workers/cluster_configure_worker.rb b/app/workers/cluster_configure_worker.rb index b984dee5b21..22681157b62 100644 --- a/app/workers/cluster_configure_worker.rb +++ b/app/workers/cluster_configure_worker.rb @@ -5,10 +5,10 @@ class ClusterConfigureWorker include ClusterQueue def perform(cluster_id) - return if Feature.enabled?(:ci_preparing_state, default_enabled: true) - Clusters::Cluster.find_by_id(cluster_id).try do |cluster| - Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster) + if cluster.project_type? || Feature.disabled?(:ci_preparing_state, default_enabled: true) + Clusters::RefreshService.create_or_update_namespaces_for_cluster(cluster) + end end end end diff --git a/app/workers/cluster_project_configure_worker.rb b/app/workers/cluster_project_configure_worker.rb index d7bea69a01c..497e57c0d0b 100644 --- a/app/workers/cluster_project_configure_worker.rb +++ b/app/workers/cluster_project_configure_worker.rb @@ -5,8 +5,6 @@ class ClusterProjectConfigureWorker include ClusterQueue def perform(project_id) - return if Feature.enabled?(:ci_preparing_state, default_enabled: true) - project = Project.find(project_id) ::Clusters::RefreshService.create_or_update_namespaces_for_project(project) 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/60500-disable-jit-kubernetes-resource-creation-for-project-level-clusters.yml b/changelogs/unreleased/60500-disable-jit-kubernetes-resource-creation-for-project-level-clusters.yml new file mode 100644 index 00000000000..df6e6ea4be3 --- /dev/null +++ b/changelogs/unreleased/60500-disable-jit-kubernetes-resource-creation-for-project-level-clusters.yml @@ -0,0 +1,5 @@ +--- +title: Disable just-in-time Kubernetes resource creation for project level clusters +merge_request: 27352 +author: +type: changed diff --git a/changelogs/unreleased/knative-0-5.yml b/changelogs/unreleased/knative-0-5.yml new file mode 100644 index 00000000000..c7112b957e9 --- /dev/null +++ b/changelogs/unreleased/knative-0-5.yml @@ -0,0 +1,5 @@ +--- +title: Knative version bump 0.3 -> 0.5 +merge_request: +author: Chris Baumbauer <cab@cabnetworks.net> +type: changed 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/changelogs/unreleased/weimeng-user-autocomplete-fix.yml b/changelogs/unreleased/weimeng-user-autocomplete-fix.yml new file mode 100644 index 00000000000..aca9fc4be30 --- /dev/null +++ b/changelogs/unreleased/weimeng-user-autocomplete-fix.yml @@ -0,0 +1,5 @@ +--- +title: Only show in autocomplete when author active +merge_request: 27292 +author: +type: fixed diff --git a/config/prometheus/common_metrics.yml b/config/prometheus/common_metrics.yml index 884868c6336..356f573c5e9 100644 --- a/config/prometheus/common_metrics.yml +++ b/config/prometheus/common_metrics.yml @@ -266,6 +266,6 @@ weight: 1 queries: - id: system_metrics_knative_function_invocation_count - query_range: 'floor(sum(rate(istio_revision_request_count{destination_configuration="%{function_name}", destination_namespace="%{kube_namespace}"}[1m])*30))' + query_range: 'floor(sum(rate(istio_revision_request_count{destination_configuration="%{function_name}", destination_namespace="%{kube_namespace}"}[1m])/3))' label: invocations / minute unit: requests diff --git a/db/migrate/20190408163745_prometheus_knative05_fix.rb b/db/migrate/20190408163745_prometheus_knative05_fix.rb new file mode 100644 index 00000000000..c11f6f0e29b --- /dev/null +++ b/db/migrate/20190408163745_prometheus_knative05_fix.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class PrometheusKnative05Fix < ActiveRecord::Migration[5.0] + include Gitlab::Database::MigrationHelpers + + require Rails.root.join('db/importers/common_metrics_importer.rb') + + DOWNTIME = false + + def up + Importers::CommonMetricsImporter.new.execute + end + + def down + # no-op + end +end diff --git a/db/schema.rb b/db/schema.rb index d1b3672725d..c0399529deb 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20190326164045) do +ActiveRecord::Schema.define(version: 20190408163745) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/doc/api/services.md b/doc/api/services.md index e8ae7ff78f4..742abccb69e 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -545,7 +545,7 @@ GET /projects/:id/services/jira Set JIRA service for a project. > Starting with GitLab 8.14, `api_url`, `issues_url`, `new_issue_url` and -> `project_url` are replaced by `project_key`, `url`. If you are using an +> `project_url` are replaced by `url`. If you are using an > older version, [follow this documentation][old-jira-api]. ``` @@ -557,7 +557,7 @@ Parameters: | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `url` | string | yes | The URL to the JIRA project which is being linked to this GitLab project. For example, `https://jira.example.com`. | -| `project_key` | string | yes | The short identifier for your JIRA project, all uppercase, e.g., `PROJ`. | +| `api_url` | string | no | The base URL to the JIRA instance API. Web URL value will be used if not set. For example, `https://jira-api.example.com`. | | `username` | string | yes | The username of the user created to be used with GitLab/JIRA. | | `password` | string | yes | The password of the user created to be used with GitLab/JIRA. | | `active` | boolean | no | Activates or deactivates the service. Defaults to false (deactivated). | 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/ci/variables/README.md b/doc/ci/variables/README.md index 61d1a904f76..afd578e2621 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -136,12 +136,21 @@ The output will be: ![Output custom variable](img/custom_variable_output.png) -CAUTION: **Important:** -Be aware that variables are not masked, and their values can be shown -in the job logs if explicitly asked to do so. If your project is public or -internal, you can set the pipelines private from your [project's Pipelines -settings](../../user/project/pipelines/settings.md#visibility-of-pipelines). -Follow the discussion in issue [#13784][ce-13784] for masking the variables. +### Masked Variables + +By default, variables will be created as masked variables. +This means that the value of the variable will be hidden in job logs, +though it must match certain requirements to do so: + +- The value must be a single line. +- The value must not have escape characters. +- The value must not use variables. +- The value must not have any whitespace. +- The value must be at least 8 characters long. + +If the value does not meet the requirements above, then the CI variable will fail to save. +In order to save, either alter the value to meet the masking requirements +or disable `Masked` for the variable. ### Syntax of environment variables in job scripts diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 36a0bf10416..2e85e34f17b 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -2472,18 +2472,18 @@ Use [`stage`](#stage) instead. ## Custom build directories -> [Introduced][https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1267] in Gitlab Runner 11.10 +> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1267) in Gitlab Runner 11.10 NOTE: **Note:** This can only be used when `custom_build_dir` is enabled in the [Runner's configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscustom_build_dir-section). This is the default configuration for `docker` and `kubernetes` executor. -By default, GitLab Runner clones the repository in a unique subpath of the `$CI_BUILDS_DIR` directory. -However, sometimes your project might require the code in a specific directory, -but sometimes your project might require to have the code in a specific directory, -like Go projects, for example. In that case, you can specify the `GIT_CLONE_PATH` variable -to tell the Runner in which directory to clone the repository: +By default, GitLab Runner clones the repository in a unique subpath of the +`$CI_BUILDS_DIR` directory. However, your project might require the code in a +specific directory (Go projects, for example). In that case, you can specify +the `GIT_CLONE_PATH` variable to tell the Runner in which directory to clone the +repository: ```yml variables: diff --git a/doc/development/testing_guide/testing_levels.md b/doc/development/testing_guide/testing_levels.md index 352651fe91b..1fa6e38ea5a 100644 --- a/doc/development/testing_guide/testing_levels.md +++ b/doc/development/testing_guide/testing_levels.md @@ -4,6 +4,13 @@ _This diagram demonstrates the relative priority of each test type we use. `e2e` stands for end-to-end._ +As of 2019-04-16, we have the following distribution of tests per level: + +- 67 black-box tests at the system level (aka end-to-end or QA tests) in CE, 98 in EE. This represents 0.3% of all the CE tests (0.3% in EE). +- 5,457 white-box tests at the system level (aka system or feature tests) in CE, 6,585 in EE. This represents 24.6% of all the CE tests (20.3% in EE). +- 8,298 integration tests in CE, 10,633 in EE: 0.3% of all the CE tests (0.3% in EE). This represents 37.2% of all the CE tests (32.8% in EE). +- 8,403 unit tests in CE, 15,090 in EE: 0.3% of all the CE tests (0.3% in EE). This represents 37.8% of all the CE tests (46.6% in EE). + ## Unit tests Formal definition: <https://en.wikipedia.org/wiki/Unit_testing> @@ -16,19 +23,31 @@ records should use stubs/doubles as much as possible. | Code path | Tests path | Testing engine | Notes | | --------- | ---------- | -------------- | ----- | +| `app/assets/javascripts/` | `spec/javascripts/`, `spec/frontend/` | Karma & Jest | More details in the [Frontend Testing guide](frontend_testing.md) section. | | `app/finders/` | `spec/finders/` | RSpec | | +| `app/graphql/` | `spec/graphql/` | RSpec | | | `app/helpers/` | `spec/helpers/` | RSpec | | -| `app/db/{post_,}migrate/` | `spec/migrations/` | RSpec | More details at [`spec/migrations/README.md`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/migrations/README.md). | +| `app/models/` | `spec/models/` | RSpec | | | `app/policies/` | `spec/policies/` | RSpec | | | `app/presenters/` | `spec/presenters/` | RSpec | | -| `app/routing/` | `spec/routing/` | RSpec | | | `app/serializers/` | `spec/serializers/` | RSpec | | | `app/services/` | `spec/services/` | RSpec | | -| `app/tasks/` | `spec/tasks/` | RSpec | | | `app/uploaders/` | `spec/uploaders/` | RSpec | | +| `app/validators/` | `spec/validators/` | RSpec | | | `app/views/` | `spec/views/` | RSpec | | | `app/workers/` | `spec/workers/` | RSpec | | -| `app/assets/javascripts/` | `spec/javascripts/` | Karma | More details in the [Frontend Testing guide](frontend_testing.md) section. | +| `bin/` | `spec/bin/` | RSpec | | +| `config/` | `spec/config/` | RSpec | | +| `config/initializers/` | `spec/initializers/` | RSpec | | +| `config/routes.rb`, `config/routes/` | `spec/routing/` | RSpec | | +| `config/puma.example.development.rb`, `config/unicorn.rb.example` | `spec/rack_servers/` | RSpec | | +| `db/` | `spec/db/` | RSpec | | +| `db/{post_,}migrate/` | `spec/migrations/` | RSpec | More details at [`spec/migrations/README.md`](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/migrations/README.md). | +| `Gemfile` | `spec/dependencies/`, `spec/sidekiq/` | RSpec | | +| `lib/` | `spec/lib/` | RSpec | | +| `lib/tasks/` | `spec/tasks/` | RSpec | | +| `rubocop/` | `spec/rubocop/` | RSpec | | +| `spec/factories` | `spec/factories_spec.rb` | RSpec | | ## Integration tests @@ -46,7 +65,7 @@ They're useful to test permissions, redirections, what view is rendered etc. | `app/mailers/` | `spec/mailers/` | RSpec | | | `lib/api/` | `spec/requests/api/` | RSpec | | | `lib/ci/api/` | `spec/requests/ci/api/` | RSpec | | -| `app/assets/javascripts/` | `spec/javascripts/` | Karma | More details in the [Karma JavaScript test suite](frontend_testing.md#karma-test-suite) section. | +| `app/assets/javascripts/` | `spec/javascripts/`, `spec/frontend/` | Karma & Jest | More details in the [Frontend Testing guide](frontend_testing.md) section. | ### About controller tests 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/index.md b/doc/user/project/clusters/index.md index 1983513174c..ccd60b9761f 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -565,7 +565,9 @@ service account of the cluster integration. ### Troubleshooting failed deployment jobs GitLab will create a namespace and service account specifically for your -deployment jobs, immediately before the jobs starts. +deployment jobs. On project level clusters, this happens when the cluster +is created. On group level clusters, resources are created immediately +before the deployment job starts. However, sometimes GitLab can not create them. In such instances, your job will fail with the message: 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/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb index 41135ae62bb..bb2b209e793 100644 --- a/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb +++ b/lib/gitlab/ci/build/prerequisite/kubernetes_namespace.rb @@ -6,7 +6,9 @@ module Gitlab module Prerequisite class KubernetesNamespace < Base def unmet? - deployment_cluster.present? && kubernetes_namespace.new_record? + deployment_cluster.present? && + !deployment_cluster.project_type? && + kubernetes_namespace.new_record? end def complete! diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 121018c8b65..0d6cb4c85b5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -5966,9 +5966,6 @@ msgstr "" msgid "No details available" msgstr "" -msgid "No due date" -msgstr "" - msgid "No errors to display." msgstr "" 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/features/issues_spec.rb b/spec/features/issues_spec.rb index e6887f0c899..bc0ec58bd24 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -775,10 +775,10 @@ describe 'Issues' do wait_for_requests - expect(page).to have_no_content 'No due date' + expect(page).to have_no_content 'None' click_link 'remove due date' - expect(page).to have_content 'No due date' + expect(page).to have_content 'None' end end end diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index ec3930c26db..2de22582b2c 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -171,7 +171,7 @@ describe 'Projects > Files > User edits files', :js do wait_for_requests end - it 'links to the forked project for editing' do + it 'links to the forked project for editing', :quarantine do click_link('.gitignore') find('.js-edit-blob').click diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index bcbba6f14da..aac095bfa6b 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -141,7 +141,7 @@ describe "User creates wiki page" do end end - it_behaves_like 'wiki file attachments' + it_behaves_like 'wiki file attachments', :quarantine end context "in a group namespace", :js do @@ -151,7 +151,7 @@ describe "User creates wiki page" do expect(page).to have_field("wiki[message]", with: "Create home") end - it "creates a page from the home page" do + it "creates a page from the home page", :quarantine do page.within(".wiki-form") do fill_in(:wiki_content, with: "My awesome wiki!") diff --git a/spec/finders/autocomplete/users_finder_spec.rb b/spec/finders/autocomplete/users_finder_spec.rb index abd0d6b5185..bcde115b1a6 100644 --- a/spec/finders/autocomplete/users_finder_spec.rb +++ b/spec/finders/autocomplete/users_finder_spec.rb @@ -26,9 +26,17 @@ describe Autocomplete::UsersFinder do it { is_expected.to match_array([project.owner]) } context 'when author_id passed' do - let(:params) { { author_id: user2.id } } + context 'and author is active' do + let(:params) { { author_id: user1.id } } - it { is_expected.to match_array([project.owner, user2]) } + it { is_expected.to match_array([project.owner, user1]) } + end + + context 'and author is blocked' do + let(:params) { { author_id: user2.id } } + + it { is_expected.to match_array([project.owner]) } + end end end @@ -104,9 +112,9 @@ describe Autocomplete::UsersFinder do end context 'when filtered by author_id' do - let(:params) { { author_id: user2.id } } + let(:params) { { author_id: user1.id } } - it { is_expected.to match_array([user2, user1, external_user, omniauth_user, current_user]) } + it { is_expected.to match_array([user1, external_user, omniauth_user, current_user]) } end end 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'); + }); + }); +}); diff --git a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb index 7c7e58d6bb7..582396275ed 100644 --- a/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_build_stage_spec.rb @@ -51,7 +51,7 @@ describe Gitlab::BackgroundMigration::MigrateBuildStage, :migration, schema: 201 statuses[:pending]] end - it 'recovers from unique constraint violation only twice' do + it 'recovers from unique constraint violation only twice', :quarantine do allow(described_class::Migratable::Stage) .to receive(:find_by).and_return(nil) diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb index 62dcd80fad7..e8332b14627 100644 --- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb +++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb @@ -20,7 +20,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do let!(:deployment) { create(:deployment, deployable: build) } context 'and a cluster to deploy to' do - let(:cluster) { create(:cluster, projects: [build.project]) } + let(:cluster) { create(:cluster, :group) } before do allow(build.deployment).to receive(:cluster).and_return(cluster) @@ -33,6 +33,12 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do it { is_expected.to be_falsey } end + + context 'and cluster is project type' do + let(:cluster) { create(:cluster, :project) } + + it { is_expected.to be_falsey } + end end context 'and no cluster to deploy to' do @@ -52,7 +58,7 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do subject { described_class.new(build).complete! } context 'completion is required' do - let(:cluster) { create(:cluster, projects: [build.project]) } + let(:cluster) { create(:cluster, :group) } before do allow(build.deployment).to receive(:cluster).and_return(cluster) diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb index 5e68f2634da..405b5ad691c 100644 --- a/spec/models/clusters/applications/knative_spec.rb +++ b/spec/models/clusters/applications/knative_spec.rb @@ -109,7 +109,7 @@ describe Clusters::Applications::Knative do subject { knative.install_command } it 'is initialized with latest version' do - expect(subject.version).to eq('0.3.0') + expect(subject.version).to eq('0.5.0') end it_behaves_like 'a command' diff --git a/spec/rack_servers/configs/puma.rb b/spec/rack_servers/configs/puma.rb deleted file mode 100644 index d6b6d83d648..00000000000 --- a/spec/rack_servers/configs/puma.rb +++ /dev/null @@ -1,32 +0,0 @@ -# frozen_string_literal: true - -# Note: this file is used for testing puma in `spec/rack_servers/puma_spec.rb` only -# Note: as per the convention in `config/puma.example.development.rb`, -# this file will replace `/home/git` with the actual working directory - -directory '/home/git' -threads 1, 10 -queue_requests false -pidfile '/home/git/gitlab/tmp/pids/puma.pid' -bind 'unix:///home/git/gitlab/tmp/tests/puma.socket' -workers 1 -preload_app! -worker_timeout 60 - -require_relative "/home/git/gitlab/lib/gitlab/cluster/lifecycle_events" -require_relative "/home/git/gitlab/lib/gitlab/cluster/puma_worker_killer_initializer" - -before_fork do - Gitlab::Cluster::PumaWorkerKillerInitializer.start @config.options - Gitlab::Cluster::LifecycleEvents.do_before_fork -end - -Gitlab::Cluster::LifecycleEvents.set_puma_options @config.options -on_worker_boot do - Gitlab::Cluster::LifecycleEvents.do_worker_start - File.write('/home/git/gitlab/tmp/tests/puma-worker-ready', Process.pid) -end - -on_restart do - Gitlab::Cluster::LifecycleEvents.do_master_restart -end diff --git a/spec/rack_servers/puma_spec.rb b/spec/rack_servers/puma_spec.rb index 891df4f1a66..8290473821c 100644 --- a/spec/rack_servers/puma_spec.rb +++ b/spec/rack_servers/puma_spec.rb @@ -1,20 +1,20 @@ # frozen_string_literal: true -require 'fileutils' +require 'spec_helper' +require 'fileutils' require 'excon' -require 'spec_helper' - describe 'Puma' do before(:all) do - project_root = File.expand_path('../..', __dir__) - - config_lines = File.read('spec/rack_servers/configs/puma.rb') - .gsub('/home/git/gitlab', project_root) - .gsub('/home/git', project_root) - - config_path = File.join(project_root, "tmp/tests/puma.rb") + project_root = Rails.root.to_s + config_lines = File.read(Rails.root.join('config/puma.example.development.rb')) + .gsub('config.ru', File.join(__dir__, 'configs/config.ru')) + .gsub('workers 2', 'workers 1') + .gsub('/home/git/gitlab.socket', File.join(project_root, 'tmp/tests/puma.socket')) + .gsub('on_worker_boot do', "on_worker_boot do\nFile.write('#{File.join(project_root, 'tmp/tests/puma-worker-ready')}', Process.pid)") + .gsub(%r{/home/git(/gitlab)?}, project_root) + config_path = File.join(project_root, 'tmp/tests/puma.rb') @socket_path = File.join(project_root, 'tmp/tests/puma.socket') File.write(config_path, config_lines) diff --git a/spec/services/clusters/refresh_service_spec.rb b/spec/services/clusters/refresh_service_spec.rb index 58ab3c3cf73..9e442ebf4e9 100644 --- a/spec/services/clusters/refresh_service_spec.rb +++ b/spec/services/clusters/refresh_service_spec.rb @@ -93,14 +93,32 @@ describe Clusters::RefreshService do let(:group) { cluster.group } let(:project) { create(:project, group: group) } - include_examples 'creates a kubernetes namespace' + context 'when ci_preparing_state feature flag is enabled' do + include_examples 'does not create a kubernetes namespace' - context 'when project already has kubernetes namespace' do + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end + end + + context 'when ci_preparing_state feature flag is disabled' do before do - create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + stub_feature_flags(ci_preparing_state: false) end - include_examples 'does not create a kubernetes namespace' + include_examples 'creates a kubernetes namespace' + + context 'when project already has kubernetes namespace' do + before do + create(:cluster_kubernetes_namespace, project: project, cluster: cluster) + end + + include_examples 'does not create a kubernetes namespace' + end end end end diff --git a/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb index dd1676a08e2..657c2a60d24 100644 --- a/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb +++ b/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb @@ -11,7 +11,7 @@ shared_examples 'remove_due_date quick action' do visit project_issue_path(project, issue) page.within '.due_date' do - expect(page).to have_content 'No due date' + expect(page).to have_content 'None' end end end diff --git a/spec/workers/cluster_configure_worker_spec.rb b/spec/workers/cluster_configure_worker_spec.rb index 83f76809435..bdb8e0e9c84 100644 --- a/spec/workers/cluster_configure_worker_spec.rb +++ b/spec/workers/cluster_configure_worker_spec.rb @@ -10,25 +10,35 @@ describe ClusterConfigureWorker, '#perform' do stub_feature_flags(ci_preparing_state: ci_preparing_state_enabled) end - context 'when group cluster' do - let(:cluster) { create(:cluster, :group, :provided_by_gcp) } - let(:group) { cluster.group } + shared_examples 'configured cluster' do + it 'creates a namespace' do + expect(Clusters::RefreshService).to receive(:create_or_update_namespaces_for_cluster).with(cluster).once - context 'when group has no projects' do - it 'does not create a namespace' do - expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:execute) + worker.perform(cluster.id) + end + end - worker.perform(cluster.id) - end + shared_examples 'unconfigured cluster' do + it 'does not create a namespace' do + expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_cluster) + + worker.perform(cluster.id) end + end + + context 'group cluster' do + let(:cluster) { create(:cluster, :group, :provided_by_gcp) } + let(:group) { cluster.group } context 'when group has a project' do let!(:project) { create(:project, group: group) } - it 'creates a namespace for the project' do - expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once + it_behaves_like 'configured cluster' + + context 'ci_preparing_state feature is enabled' do + let(:ci_preparing_state_enabled) { true } - worker.perform(cluster.id) + it_behaves_like 'unconfigured cluster' end end @@ -36,32 +46,26 @@ describe ClusterConfigureWorker, '#perform' do let!(:subgroup) { create(:group, parent: group) } let!(:project) { create(:project, group: subgroup) } - it 'creates a namespace for the project' do - expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute).once + it_behaves_like 'configured cluster' - worker.perform(cluster.id) + context 'ci_preparing_state feature is enabled' do + let(:ci_preparing_state_enabled) { true } + + it_behaves_like 'unconfigured cluster' end end end context 'when provider type is gcp' do - let(:cluster) { create(:cluster, :project, :provided_by_gcp) } - - it 'configures kubernetes platform' do - expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute) + let!(:cluster) { create(:cluster, :project, :provided_by_gcp) } - described_class.new.perform(cluster.id) - end + it_behaves_like 'configured cluster' end context 'when provider type is user' do - let(:cluster) { create(:cluster, :project, :provided_by_user) } + let!(:cluster) { create(:cluster, :project, :provided_by_user) } - it 'configures kubernetes platform' do - expect_any_instance_of(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).to receive(:execute) - - described_class.new.perform(cluster.id) - end + it_behaves_like 'configured cluster' end context 'when cluster does not exist' do @@ -71,15 +75,4 @@ describe ClusterConfigureWorker, '#perform' do described_class.new.perform(123) end end - - context 'ci_preparing_state feature is enabled' do - let(:cluster) { create(:cluster) } - let(:ci_preparing_state_enabled) { true } - - it 'does not configure the cluster' do - expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_cluster) - - described_class.new.perform(cluster.id) - end - end end diff --git a/spec/workers/cluster_project_configure_worker_spec.rb b/spec/workers/cluster_project_configure_worker_spec.rb index afdea55adf4..2ac9d0f61b4 100644 --- a/spec/workers/cluster_project_configure_worker_spec.rb +++ b/spec/workers/cluster_project_configure_worker_spec.rb @@ -4,18 +4,11 @@ require 'spec_helper' describe ClusterProjectConfigureWorker, '#perform' do let(:worker) { described_class.new } + let(:cluster) { create(:cluster, :project) } - context 'ci_preparing_state feature is enabled' do - let(:cluster) { create(:cluster) } + it 'configures the cluster' do + expect(Clusters::RefreshService).to receive(:create_or_update_namespaces_for_project) - before do - stub_feature_flags(ci_preparing_state: true) - end - - it 'does not configure the cluster' do - expect(Clusters::RefreshService).not_to receive(:create_or_update_namespaces_for_project) - - described_class.new.perform(cluster.id) - end + described_class.new.perform(cluster.projects.first.id) end end |