diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-05 12:09:00 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-05 12:09:00 +0300 |
commit | 015890a1b77cd90e9ffeb704944d1fb63b0ce555 (patch) | |
tree | bcf07119c9492fb59e637e732b3427d752c0cc49 | |
parent | d10e04a10b5c7bf4e46589f05e8b63db30b3972d (diff) |
Add latest changes from gitlab-org/gitlab@master
97 files changed, 1688 insertions, 889 deletions
diff --git a/app/assets/javascripts/notes/components/discussion_filter_note.vue b/app/assets/javascripts/notes/components/discussion_filter_note.vue index ff70c89cd39..83326279423 100644 --- a/app/assets/javascripts/notes/components/discussion_filter_note.vue +++ b/app/assets/javascripts/notes/components/discussion_filter_note.vue @@ -1,28 +1,19 @@ <script> -/* eslint-disable vue/no-v-html */ -import { GlButton, GlIcon } from '@gitlab/ui'; -import { __, sprintf } from '~/locale'; +import { GlButton, GlIcon, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; import notesEventHub from '../event_hub'; export default { + i18n: { + information: s__( + "Notes|You're only seeing %{boldStart}other activity%{boldEnd} in the feed. To add a comment, switch to one of the following options.", + ), + }, components: { GlButton, GlIcon, - }, - computed: { - timelineContent() { - return sprintf( - __( - "You're only seeing %{startTag}other activity%{endTag} in the feed. To add a comment, switch to one of the following options.", - ), - { - startTag: `<b>`, - endTag: `</b>`, - }, - false, - ); - }, + GlSprintf, }, methods: { selectFilter(value) { @@ -41,12 +32,18 @@ export default { <gl-icon name="comment" /> </div> <div class="timeline-content"> - <div ref="timelineContent" v-html="timelineContent"></div> + <div data-testid="discussion-filter-timeline-content"> + <gl-sprintf :message="$options.i18n.information"> + <template #bold="{ content }"> + <b>{{ content }}</b> + </template> + </gl-sprintf> + </div> <div class="discussion-filter-actions mt-2"> - <gl-button ref="showAllActivity" variant="default" @click="selectFilter(0)"> + <gl-button variant="default" @click="selectFilter(0)"> {{ __('Show all activity') }} </gl-button> - <gl-button ref="showComments" variant="default" @click="selectFilter(1)"> + <gl-button variant="default" @click="selectFilter(1)"> {{ __('Show comments only') }} </gl-button> </div> diff --git a/app/graphql/types/release_links_type.rb b/app/graphql/types/release_links_type.rb index da2ef4665f2..619bb1e6c3a 100644 --- a/app/graphql/types/release_links_type.rb +++ b/app/graphql/types/release_links_type.rb @@ -25,12 +25,5 @@ module Types description: 'HTTP URL of the issues page, filtered by this release and `state=open`' field :closed_issues_url, GraphQL::STRING_TYPE, null: true, description: 'HTTP URL of the issues page, filtered by this release and `state=closed`' - - field :merge_requests_url, GraphQL::STRING_TYPE, null: true, method: :opened_merge_requests_url, - description: 'HTTP URL of the merge request page filtered by this release', - deprecated: { reason: 'Use `openedMergeRequestsUrl`', milestone: '13.6' } - field :issues_url, GraphQL::STRING_TYPE, null: true, method: :opened_issues_url, - description: 'HTTP URL of the issues page filtered by this release', - deprecated: { reason: 'Use `openedIssuesUrl`', milestone: '13.6' } end end diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb index 1efa44c39c5..d32fff14590 100644 --- a/app/models/clusters/applications/cert_manager.rb +++ b/app/models/clusters/applications/cert_manager.rb @@ -30,7 +30,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: 'certmanager', repository: repository, version: VERSION, @@ -43,7 +43,7 @@ module Clusters end def uninstall_command - Gitlab::Kubernetes::Helm::DeleteCommand.new( + helm_command_module::DeleteCommand.new( name: 'certmanager', rbac: cluster.platform_kubernetes_rbac?, files: files, diff --git a/app/models/clusters/applications/crossplane.rb b/app/models/clusters/applications/crossplane.rb index 420e56c1742..2b1a86706a4 100644 --- a/app/models/clusters/applications/crossplane.rb +++ b/app/models/clusters/applications/crossplane.rb @@ -29,7 +29,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: 'crossplane', repository: repository, version: VERSION, diff --git a/app/models/clusters/applications/elastic_stack.rb b/app/models/clusters/applications/elastic_stack.rb index 77996748b81..db18a29ec84 100644 --- a/app/models/clusters/applications/elastic_stack.rb +++ b/app/models/clusters/applications/elastic_stack.rb @@ -26,7 +26,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: 'elastic-stack', version: VERSION, rbac: cluster.platform_kubernetes_rbac?, @@ -39,7 +39,7 @@ module Clusters end def uninstall_command - Gitlab::Kubernetes::Helm::DeleteCommand.new( + helm_command_module::DeleteCommand.new( name: 'elastic-stack', rbac: cluster.platform_kubernetes_rbac?, files: files, @@ -96,7 +96,7 @@ module Clusters def post_install_script [ - "timeout -t60 sh /data/helm/elastic-stack/config/wait-for-elasticsearch.sh http://elastic-stack-elasticsearch-master:9200" + "timeout 60 sh /data/helm/elastic-stack/config/wait-for-elasticsearch.sh http://elastic-stack-elasticsearch-master:9200" ] end @@ -116,7 +116,7 @@ module Clusters # Chart version 3.0.0 moves to our own chart at https://gitlab.com/gitlab-org/charts/elastic-stack # and is not compatible with pre-existing resources. We first remove them. [ - Gitlab::Kubernetes::Helm::DeleteCommand.new( + helm_command_module::DeleteCommand.new( name: 'elastic-stack', rbac: cluster.platform_kubernetes_rbac?, files: files diff --git a/app/models/clusters/applications/fluentd.rb b/app/models/clusters/applications/fluentd.rb index c608d37be77..91aa422b859 100644 --- a/app/models/clusters/applications/fluentd.rb +++ b/app/models/clusters/applications/fluentd.rb @@ -30,7 +30,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: 'fluentd', repository: repository, version: VERSION, diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb index 4a1bcac4bb7..d1d6defb713 100644 --- a/app/models/clusters/applications/helm.rb +++ b/app/models/clusters/applications/helm.rb @@ -4,6 +4,8 @@ require 'openssl' module Clusters module Applications + # DEPRECATED: This model represents the Helm 2 Tiller server, and is no longer being actively used. + # It is being kept around for a potential cleanup of the unused Tiller server. class Helm < ApplicationRecord self.table_name = 'clusters_applications_helm' @@ -49,7 +51,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InitCommand.new( + Gitlab::Kubernetes::Helm::V2::InitCommand.new( name: name, files: files, rbac: cluster.platform_kubernetes_rbac? @@ -57,7 +59,7 @@ module Clusters end def uninstall_command - Gitlab::Kubernetes::Helm::ResetCommand.new( + Gitlab::Kubernetes::Helm::V2::ResetCommand.new( name: name, files: files, rbac: cluster.platform_kubernetes_rbac? @@ -86,19 +88,19 @@ module Clusters end def create_keys_and_certs - ca_cert = Gitlab::Kubernetes::Helm::Certificate.generate_root + ca_cert = Gitlab::Kubernetes::Helm::V2::Certificate.generate_root self.ca_key = ca_cert.key_string self.ca_cert = ca_cert.cert_string end def tiller_cert - @tiller_cert ||= ca_cert_obj.issue(expires_in: Gitlab::Kubernetes::Helm::Certificate::INFINITE_EXPIRY) + @tiller_cert ||= ca_cert_obj.issue(expires_in: Gitlab::Kubernetes::Helm::V2::Certificate::INFINITE_EXPIRY) end def ca_cert_obj return unless has_ssl? - Gitlab::Kubernetes::Helm::Certificate + Gitlab::Kubernetes::Helm::V2::Certificate .from_strings(ca_key, ca_cert) end end diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb index d5412714858..36324e7f3e0 100644 --- a/app/models/clusters/applications/ingress.rb +++ b/app/models/clusters/applications/ingress.rb @@ -62,7 +62,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: name, repository: repository, version: VERSION, diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb index 056ea355de6..ff907c6847f 100644 --- a/app/models/clusters/applications/jupyter.rb +++ b/app/models/clusters/applications/jupyter.rb @@ -39,7 +39,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: name, version: VERSION, rbac: cluster.platform_kubernetes_rbac?, diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb index 3047da12dd9..b1c3116d77c 100644 --- a/app/models/clusters/applications/knative.rb +++ b/app/models/clusters/applications/knative.rb @@ -70,7 +70,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: name, version: VERSION, rbac: cluster.platform_kubernetes_rbac?, @@ -94,7 +94,7 @@ module Clusters end def uninstall_command - Gitlab::Kubernetes::Helm::DeleteCommand.new( + helm_command_module::DeleteCommand.new( name: name, rbac: cluster.platform_kubernetes_rbac?, files: files, diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb index 7679296699f..55a9a0ccb81 100644 --- a/app/models/clusters/applications/prometheus.rb +++ b/app/models/clusters/applications/prometheus.rb @@ -67,7 +67,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: name, repository: repository, version: VERSION, @@ -79,7 +79,7 @@ module Clusters end def patch_command(values) - ::Gitlab::Kubernetes::Helm::PatchCommand.new( + helm_command_module::PatchCommand.new( name: name, repository: repository, version: version, @@ -90,7 +90,7 @@ module Clusters end def uninstall_command - Gitlab::Kubernetes::Helm::DeleteCommand.new( + helm_command_module::DeleteCommand.new( name: name, rbac: cluster.platform_kubernetes_rbac?, files: files, diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb index 6ddf552cd65..03f4caccccd 100644 --- a/app/models/clusters/applications/runner.rb +++ b/app/models/clusters/applications/runner.rb @@ -30,7 +30,7 @@ module Clusters end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new( + helm_command_module::InstallCommand.new( name: name, version: VERSION, rbac: cluster.platform_kubernetes_rbac?, diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index b94ec3c6dea..3cf5542ae76 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -79,6 +79,9 @@ module Clusters validates :cluster_type, presence: true validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true } validates :namespace_per_environment, inclusion: { in: [true, false] } + validates :helm_major_version, inclusion: { in: [2, 3] } + + default_value_for :helm_major_version, 3 validate :restrict_modification, on: :update validate :no_groups, unless: :group_type? diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb index 760576ea1eb..b82b1887308 100644 --- a/app/models/clusters/concerns/application_core.rb +++ b/app/models/clusters/concerns/application_core.rb @@ -12,6 +12,17 @@ module Clusters after_initialize :set_initial_status + def helm_command_module + case cluster.helm_major_version + when 3 + Gitlab::Kubernetes::Helm::V3 + when 2 + Gitlab::Kubernetes::Helm::V2 + else + raise "Invalid Helm major version" + end + end + def set_initial_status return unless not_installable? diff --git a/app/models/clusters/concerns/application_data.rb b/app/models/clusters/concerns/application_data.rb index 22e597e9747..00aeb7669ad 100644 --- a/app/models/clusters/concerns/application_data.rb +++ b/app/models/clusters/concerns/application_data.rb @@ -4,7 +4,7 @@ module Clusters module Concerns module ApplicationData def uninstall_command - Gitlab::Kubernetes::Helm::DeleteCommand.new( + helm_command_module::DeleteCommand.new( name: name, rbac: cluster.platform_kubernetes_rbac?, files: files diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb index 98db47deaa3..8192310ddfb 100644 --- a/app/models/pages_domain.rb +++ b/app/models/pages_domain.rb @@ -286,7 +286,7 @@ class PagesDomain < ApplicationRecord return unless domain if domain.downcase.ends_with?(Settings.pages.host.downcase) - self.errors.add(:domain, "*.#{Settings.pages.host} is restricted") + self.errors.add(:domain, "*.#{Settings.pages.host} is restricted. Please compare our documentation at https://docs.gitlab.com/ee/administration/pages/#advanced-configuration against your configuration.") end end diff --git a/changelogs/unreleased/241957-remove-v-html-from-app-assets-javascripts-notes-components-discuss.yml b/changelogs/unreleased/241957-remove-v-html-from-app-assets-javascripts-notes-components-discuss.yml new file mode 100644 index 00000000000..ee781be5134 --- /dev/null +++ b/changelogs/unreleased/241957-remove-v-html-from-app-assets-javascripts-notes-components-discuss.yml @@ -0,0 +1,5 @@ +--- +title: Replace v-html with GlSprintf in notes/.../discussion_filter_note.vue +merge_request: 41482 +author: Takuya Noguchi +type: other diff --git a/changelogs/unreleased/add-helm3-support-for-cluster-apps.yml b/changelogs/unreleased/add-helm3-support-for-cluster-apps.yml new file mode 100644 index 00000000000..334f5e0ee36 --- /dev/null +++ b/changelogs/unreleased/add-helm3-support-for-cluster-apps.yml @@ -0,0 +1,5 @@ +--- +title: Use Helm 3 by default for GitLab-managed apps in new clusters +merge_request: 46267 +author: +type: changed diff --git a/config/initializers/0_inject_feature_flags.rb b/config/initializers/0_inject_feature_flags.rb index 4de762742d1..78fd67b97df 100644 --- a/config/initializers/0_inject_feature_flags.rb +++ b/config/initializers/0_inject_feature_flags.rb @@ -14,7 +14,6 @@ if Gitlab.ee? && Gitlab.dev_or_test_env? # being unique to licensed names. These feature flags should be reworked to # be "development" with explicit check IGNORED_FEATURE_FLAGS = %i[ - feature_flags_related_issues group_wikis swimlanes minimal_access_role diff --git a/db/migrate/20201028184640_add_helm_major_version_to_clusters.rb b/db/migrate/20201028184640_add_helm_major_version_to_clusters.rb new file mode 100644 index 00000000000..2169fd41826 --- /dev/null +++ b/db/migrate/20201028184640_add_helm_major_version_to_clusters.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# See https://docs.gitlab.com/ee/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddHelmMajorVersionToClusters < ActiveRecord::Migration[6.0] + DOWNTIME = false + + def change + add_column(:clusters, :helm_major_version, :integer, default: 2, null: false) + end +end diff --git a/db/schema_migrations/20201028184640 b/db/schema_migrations/20201028184640 new file mode 100644 index 00000000000..4cac95e4e7b --- /dev/null +++ b/db/schema_migrations/20201028184640 @@ -0,0 +1 @@ +5520cca016af07fb2e009c0e3254362f106a9cc808cbb61e280221be82be1b25
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 8c278442790..ee43e18c517 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -10967,7 +10967,8 @@ CREATE TABLE clusters ( namespace_per_environment boolean DEFAULT true NOT NULL, management_project_id integer, cleanup_status smallint DEFAULT 1 NOT NULL, - cleanup_status_reason text + cleanup_status_reason text, + helm_major_version integer DEFAULT 2 NOT NULL ); CREATE TABLE clusters_applications_cert_managers ( diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index e39c8919706..39bcae58bdc 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -17420,16 +17420,6 @@ type ReleaseLinks { editUrl: String """ - HTTP URL of the issues page filtered by this release. Deprecated in 13.6: Use `openedIssuesUrl` - """ - issuesUrl: String @deprecated(reason: "Use `openedIssuesUrl`. Deprecated in 13.6") - - """ - HTTP URL of the merge request page filtered by this release. Deprecated in 13.6: Use `openedMergeRequestsUrl` - """ - mergeRequestsUrl: String @deprecated(reason: "Use `openedMergeRequestsUrl`. Deprecated in 13.6") - - """ HTTP URL of the merge request page , filtered by this release and `state=merged` """ mergedMergeRequestsUrl: String diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 1e5ac96f3ea..1311991b485 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -50231,34 +50231,6 @@ "deprecationReason": null }, { - "name": "issuesUrl", - "description": "HTTP URL of the issues page filtered by this release. Deprecated in 13.6: Use `openedIssuesUrl`", - "args": [ - - ], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "Use `openedIssuesUrl`. Deprecated in 13.6" - }, - { - "name": "mergeRequestsUrl", - "description": "HTTP URL of the merge request page filtered by this release. Deprecated in 13.6: Use `openedMergeRequestsUrl`", - "args": [ - - ], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "Use `openedMergeRequestsUrl`. Deprecated in 13.6" - }, - { "name": "mergedMergeRequestsUrl", "description": "HTTP URL of the merge request page , filtered by this release and `state=merged`", "args": [ diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 3d3aa2f4bcb..be355d77e31 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -2435,8 +2435,6 @@ Evidence for a release. | `closedIssuesUrl` | String | HTTP URL of the issues page, filtered by this release and `state=closed` | | `closedMergeRequestsUrl` | String | HTTP URL of the merge request page , filtered by this release and `state=closed` | | `editUrl` | String | HTTP URL of the release's edit page | -| `issuesUrl` **{warning-solid}** | String | **Deprecated:** Use `openedIssuesUrl`. Deprecated in 13.6 | -| `mergeRequestsUrl` **{warning-solid}** | String | **Deprecated:** Use `openedMergeRequestsUrl`. Deprecated in 13.6 | | `mergedMergeRequestsUrl` | String | HTTP URL of the merge request page , filtered by this release and `state=merged` | | `openedIssuesUrl` | String | HTTP URL of the issues page, filtered by this release and `state=open` | | `openedMergeRequestsUrl` | String | HTTP URL of the merge request page, filtered by this release and `state=open` | diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb index ac43617914a..44a46c5861e 100644 --- a/lib/api/entities/release.rb +++ b/lib/api/entities/release.rb @@ -30,8 +30,6 @@ module API expose :evidences, using: Entities::Releases::Evidence, expose_nil: false, if: ->(_, _) { can_download_code? } expose :_links do expose :self_url, as: :self, expose_nil: false - expose :opened_merge_requests_url, as: :merge_requests_url, expose_nil: false - expose :opened_issues_url, as: :issues_url, expose_nil: false expose :edit_url, expose_nil: false end diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb index 1740032e5c7..70fcc1d586a 100644 --- a/lib/gitlab/ci/config/entry/bridge.rb +++ b/lib/gitlab/ci/config/entry/bridge.rb @@ -18,7 +18,6 @@ module Gitlab validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS with_options allow_nil: true do - validates :allow_failure, boolean: true validates :when, inclusion: { in: ALLOWED_WHEN, message: "should be one of: #{ALLOWED_WHEN.join(', ')}" @@ -48,7 +47,7 @@ module Gitlab inherit: false, metadata: { allowed_needs: %i[job bridge] } - attributes :when, :allow_failure + attributes :when def self.matching?(name, config) !name.to_s.start_with?('.') && @@ -60,14 +59,6 @@ module Gitlab true end - def manual_action? - self.when == 'manual' - end - - def ignored? - allow_failure.nil? ? manual_action? : allow_failure - end - def value super.merge( trigger: (trigger_value if trigger_defined?), diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index ecc2c5cb729..1ce7060df22 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -24,7 +24,6 @@ module Gitlab validates :script, presence: true with_options allow_nil: true do - validates :allow_failure, boolean: true validates :when, inclusion: { in: ALLOWED_WHEN, message: "should be one of: #{ALLOWED_WHEN.join(', ')}" @@ -118,7 +117,7 @@ module Gitlab description: 'Parallel configuration for this job.', inherit: false - attributes :script, :tags, :allow_failure, :when, :dependencies, + attributes :script, :tags, :when, :dependencies, :needs, :retry, :parallel, :start_in, :interruptible, :timeout, :resource_group, :release @@ -141,18 +140,10 @@ module Gitlab end end - def manual_action? - self.when == 'manual' - end - def delayed? self.when == 'delayed' end - def ignored? - allow_failure.nil? ? manual_action? : allow_failure - end - def value super.merge( before_script: before_script_value, diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb index f10c509d0cc..c0315e5f901 100644 --- a/lib/gitlab/ci/config/entry/processable.rb +++ b/lib/gitlab/ci/config/entry/processable.rb @@ -32,6 +32,7 @@ module Gitlab with_options allow_nil: true do validates :extends, array_of_strings_or_string: true validates :rules, array_of_hashes: true + validates :allow_failure, boolean: true end end @@ -64,7 +65,7 @@ module Gitlab inherit: false, default: {} - attributes :extends, :rules + attributes :extends, :rules, :allow_failure end def compose!(deps = nil) @@ -136,6 +137,14 @@ module Gitlab root_variables.merge(variables_value.to_h) end + + def manual_action? + self.when == 'manual' + end + + def ignored? + allow_failure.nil? ? manual_action? : allow_failure + end end end end diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index 7b8689069d8..8e78f6e274a 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -55,9 +55,17 @@ module Gitlab end def project_tree - @project_tree ||= Gitlab::ImportExport::Project::TreeRestorer.new(user: current_user, - shared: shared, - project: project) + @project_tree ||= project_tree_class.new(user: current_user, + shared: shared, + project: project) + end + + def project_tree_class + sample_data_template? ? Gitlab::ImportExport::Project::Sample::TreeRestorer : Gitlab::ImportExport::Project::TreeRestorer + end + + def sample_data_template? + project&.import_data&.data&.dig('sample_data') end def avatar_restorer diff --git a/lib/gitlab/import_export/project/sample/relation_factory.rb b/lib/gitlab/import_export/project/sample/relation_factory.rb new file mode 100644 index 00000000000..6e59174f9a3 --- /dev/null +++ b/lib/gitlab/import_export/project/sample/relation_factory.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Gitlab + module ImportExport + module Project + module Sample + class RelationFactory < Project::RelationFactory + DATE_MODELS = %i[issues milestones].freeze + + def initialize(date_calculator:, **args) + super(**args) + + @date_calculator = date_calculator + end + + private + + def setup_models + super + + # Override due date attributes in data hash for Sample Data templates + # Dates are moved by taking the closest one to average and moving that (and rest around it) to the date of import + override_date_attributes + end + + def override_date_attributes + return unless DATE_MODELS.include?(@relation_name) + + @relation_hash['start_date'] = calculate_by_closest_date(@relation_hash['start_date']&.to_time) + @relation_hash['due_date'] = calculate_by_closest_date(@relation_hash['due_date']&.to_time) + end + + def calculate_by_closest_date(date) + return unless date + + @date_calculator.calculate_by_closest_date_to_average(date) + end + end + end + end + end +end diff --git a/lib/gitlab/import_export/project/sample/relation_tree_restorer.rb b/lib/gitlab/import_export/project/sample/relation_tree_restorer.rb new file mode 100644 index 00000000000..44ccb67a531 --- /dev/null +++ b/lib/gitlab/import_export/project/sample/relation_tree_restorer.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module Gitlab + module ImportExport + module Project + module Sample + class RelationTreeRestorer < ImportExport::RelationTreeRestorer + def initialize(*args) + super + + @date_calculator = Gitlab::ImportExport::Project::Sample::DateCalculator.new(dates) + end + + private + + def relation_factory_params(*args) + super.merge(date_calculator: @date_calculator) + end + + def dates + return [] if relation_reader.legacy? + + RelationFactory::DATE_MODELS.flat_map do |tag| + relation_reader.consume_relation(@importable_path, tag, mark_as_consumed: false).map do |model| + model.first['due_date'] + end + end + end + end + end + end + end +end diff --git a/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb b/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb deleted file mode 100644 index 6285898fc63..00000000000 --- a/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb +++ /dev/null @@ -1,50 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module ImportExport - module Project - module Sample - class SampleDataRelationTreeRestorer < RelationTreeRestorer - DATE_MODELS = %i[issues milestones].freeze - - def initialize(*args) - super - - date_calculator - end - - private - - def build_relation(relation_key, relation_definition, data_hash) - # Override due date attributes in data hash for Sample Data templates - # Dates are moved by taking the closest one to average and moving that (and rest around it) to the date of import - # TODO: To move this logic to RelationFactory (see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465333) - override_date_attributes!(relation_key, data_hash) - super - end - - def override_date_attributes!(relation_key, data_hash) - return unless DATE_MODELS.include?(relation_key.to_sym) - - data_hash['start_date'] = date_calculator.calculate_by_closest_date_to_average(data_hash['start_date'].to_time) unless data_hash['start_date'].nil? - data_hash['due_date'] = date_calculator.calculate_by_closest_date_to_average(data_hash['due_date'].to_time) unless data_hash['due_date'].nil? - end - - def dates - return if relation_reader.legacy? - - DATE_MODELS.flat_map do |tag| - relation_reader.consume_relation(@importable_path, tag, mark_as_consumed: false).map do |model| - model.first['due_date'] - end - end - end - - def date_calculator - @date_calculator ||= Gitlab::ImportExport::Project::Sample::DateCalculator.new(dates) - end - end - end - end - end -end diff --git a/lib/gitlab/import_export/project/sample/tree_restorer.rb b/lib/gitlab/import_export/project/sample/tree_restorer.rb new file mode 100644 index 00000000000..1d4b5328cb9 --- /dev/null +++ b/lib/gitlab/import_export/project/sample/tree_restorer.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Gitlab + module ImportExport + module Project + module Sample + class TreeRestorer < Project::TreeRestorer + def relation_tree_restorer_class + RelationTreeRestorer + end + + def relation_factory + RelationFactory + end + end + end + end + end +end diff --git a/lib/gitlab/import_export/project/tree_restorer.rb b/lib/gitlab/import_export/project/tree_restorer.rb index b1d647281ab..fb9e5be1877 100644 --- a/lib/gitlab/import_export/project/tree_restorer.rb +++ b/lib/gitlab/import_export/project/tree_restorer.rb @@ -85,11 +85,7 @@ module Gitlab end def relation_tree_restorer_class - sample_data_template? ? Sample::SampleDataRelationTreeRestorer : RelationTreeRestorer - end - - def sample_data_template? - @project&.import_data&.data&.dig('sample_data') + RelationTreeRestorer end def members_mapper diff --git a/lib/gitlab/kubernetes/helm/base_command.rb b/lib/gitlab/kubernetes/helm/base_command.rb deleted file mode 100644 index 49d2969f7f3..00000000000 --- a/lib/gitlab/kubernetes/helm/base_command.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Kubernetes - module Helm - class BaseCommand - attr_reader :name, :files - - def initialize(rbac:, name:, files:) - @rbac = rbac - @name = name - @files = files - end - - def rbac? - @rbac - end - - def pod_resource - pod_service_account_name = rbac? ? service_account_name : nil - - Gitlab::Kubernetes::Helm::Pod.new(self, namespace, service_account_name: pod_service_account_name).generate - end - - def generate_script - <<~HEREDOC - set -xeo pipefail - HEREDOC - end - - def pod_name - "install-#{name}" - end - - def config_map_resource - Gitlab::Kubernetes::ConfigMap.new(name, files).generate - end - - def service_account_resource - return unless rbac? - - Gitlab::Kubernetes::ServiceAccount.new(service_account_name, namespace).generate - end - - def cluster_role_binding_resource - return unless rbac? - - subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: namespace }] - - Gitlab::Kubernetes::ClusterRoleBinding.new( - cluster_role_binding_name, - cluster_role_name, - subjects - ).generate - end - - def file_names - files.keys - end - - private - - def files_dir - "/data/helm/#{name}/config" - end - - def namespace - Gitlab::Kubernetes::Helm::NAMESPACE - end - - def service_account_name - Gitlab::Kubernetes::Helm::SERVICE_ACCOUNT - end - - def cluster_role_binding_name - Gitlab::Kubernetes::Helm::CLUSTER_ROLE_BINDING - end - - def cluster_role_name - Gitlab::Kubernetes::Helm::CLUSTER_ROLE - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/certificate.rb b/lib/gitlab/kubernetes/helm/certificate.rb deleted file mode 100644 index 598714e0874..00000000000 --- a/lib/gitlab/kubernetes/helm/certificate.rb +++ /dev/null @@ -1,73 +0,0 @@ -# frozen_string_literal: true -module Gitlab - module Kubernetes - module Helm - class Certificate - INFINITE_EXPIRY = 1000.years - SHORT_EXPIRY = 30.minutes - - attr_reader :key, :cert - - def key_string - @key.to_s - end - - def cert_string - @cert.to_pem - end - - def self.from_strings(key_string, cert_string) - key = OpenSSL::PKey::RSA.new(key_string) - cert = OpenSSL::X509::Certificate.new(cert_string) - new(key, cert) - end - - def self.generate_root - _issue(signed_by: nil, expires_in: INFINITE_EXPIRY, certificate_authority: true) - end - - def issue(expires_in: SHORT_EXPIRY) - self.class._issue(signed_by: self, expires_in: expires_in, certificate_authority: false) - end - - private - - def self._issue(signed_by:, expires_in:, certificate_authority:) - key = OpenSSL::PKey::RSA.new(4096) - public_key = key.public_key - - subject = OpenSSL::X509::Name.parse("/C=US") - - cert = OpenSSL::X509::Certificate.new - cert.subject = subject - - cert.issuer = signed_by&.cert&.subject || subject - - cert.not_before = Time.now - cert.not_after = expires_in.from_now - cert.public_key = public_key - cert.serial = 0x0 - cert.version = 2 - - if certificate_authority - extension_factory = OpenSSL::X509::ExtensionFactory.new - extension_factory.subject_certificate = cert - extension_factory.issuer_certificate = cert - cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash')) - cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)) - cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true)) - end - - cert.sign(signed_by&.key || key, OpenSSL::Digest::SHA256.new) - - new(key, cert) - end - - def initialize(key, cert) - @key = key - @cert = cert - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/client_command.rb b/lib/gitlab/kubernetes/helm/client_command.rb deleted file mode 100644 index a9e93c0c90e..00000000000 --- a/lib/gitlab/kubernetes/helm/client_command.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Kubernetes - module Helm - module ClientCommand - def init_command - <<~SHELL.chomp - export HELM_HOST="localhost:44134" - tiller -listen ${HELM_HOST} -alsologtostderr & - helm init --client-only - SHELL - end - - def repository_command - ['helm', 'repo', 'add', name, repository].shelljoin if repository - end - - private - - def repository_update_command - 'helm repo update' - end - - def optional_tls_flags - return [] unless files.key?(:'ca.pem') - - [ - '--tls', - '--tls-ca-cert', "#{files_dir}/ca.pem", - '--tls-cert', "#{files_dir}/cert.pem", - '--tls-key', "#{files_dir}/key.pem" - ] - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/delete_command.rb b/lib/gitlab/kubernetes/helm/delete_command.rb deleted file mode 100644 index f8b9601bc98..00000000000 --- a/lib/gitlab/kubernetes/helm/delete_command.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Kubernetes - module Helm - class DeleteCommand < BaseCommand - include ClientCommand - - attr_reader :predelete, :postdelete - - def initialize(predelete: nil, postdelete: nil, **args) - super(**args) - @predelete = predelete - @postdelete = postdelete - end - - def generate_script - super + [ - init_command, - predelete, - delete_command, - postdelete - ].compact.join("\n") - end - - def pod_name - "uninstall-#{name}" - end - - def delete_command - ['helm', 'delete', '--purge', name].shelljoin - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/init_command.rb b/lib/gitlab/kubernetes/helm/init_command.rb deleted file mode 100644 index e4844e255c5..00000000000 --- a/lib/gitlab/kubernetes/helm/init_command.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Kubernetes - module Helm - class InitCommand < BaseCommand - def generate_script - super + [ - init_helm_command - ].join("\n") - end - - private - - def init_helm_command - command = %w[helm init] + init_command_flags - - command.shelljoin - end - - def init_command_flags - tls_flags + optional_service_account_flag - end - - def tls_flags - [ - '--tiller-tls', - '--tiller-tls-verify', - '--tls-ca-cert', "#{files_dir}/ca.pem", - '--tiller-tls-cert', "#{files_dir}/cert.pem", - '--tiller-tls-key', "#{files_dir}/key.pem" - ] - end - - def optional_service_account_flag - return [] unless rbac? - - ['--service-account', service_account_name] - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb deleted file mode 100644 index d166842fce6..00000000000 --- a/lib/gitlab/kubernetes/helm/install_command.rb +++ /dev/null @@ -1,85 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Kubernetes - module Helm - class InstallCommand < BaseCommand - include ClientCommand - - attr_reader :chart, :repository, :preinstall, :postinstall - attr_accessor :version - - def initialize(chart:, version: nil, repository: nil, preinstall: nil, postinstall: nil, **args) - super(**args) - @chart = chart - @version = version - @repository = repository - @preinstall = preinstall - @postinstall = postinstall - end - - def generate_script - super + [ - init_command, - repository_command, - repository_update_command, - preinstall, - install_command, - postinstall - ].compact.join("\n") - end - - private - - # Uses `helm upgrade --install` which means we can use this for both - # installation and uprade of applications - def install_command - command = ['helm', 'upgrade', name, chart] + - install_flag + - rollback_support_flag + - reset_values_flag + - optional_version_flag + - rbac_create_flag + - namespace_flag + - value_flag - - command.shelljoin - end - - def install_flag - ['--install'] - end - - def reset_values_flag - ['--reset-values'] - end - - def value_flag - ['-f', "/data/helm/#{name}/config/values.yaml"] - end - - def namespace_flag - ['--namespace', Gitlab::Kubernetes::Helm::NAMESPACE] - end - - def rbac_create_flag - if rbac? - %w[--set rbac.create=true,rbac.enabled=true] - else - %w[--set rbac.create=false,rbac.enabled=false] - end - end - - def optional_version_flag - return [] unless version - - ['--version', version] - end - - def rollback_support_flag - ['--atomic', '--cleanup-on-fail'] - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/patch_command.rb b/lib/gitlab/kubernetes/helm/patch_command.rb deleted file mode 100644 index a33dbdac134..00000000000 --- a/lib/gitlab/kubernetes/helm/patch_command.rb +++ /dev/null @@ -1,65 +0,0 @@ -# frozen_string_literal: true - -# PatchCommand is for updating values in installed charts without overwriting -# existing values. -module Gitlab - module Kubernetes - module Helm - class PatchCommand < BaseCommand - include ClientCommand - - attr_reader :chart, :repository - attr_accessor :version - - def initialize(chart:, version:, repository: nil, **args) - super(**args) - - # version is mandatory to prevent chart mismatches - # we do not want our values interpreted in the context of the wrong version - raise ArgumentError, 'version is required' if version.blank? - - @chart = chart - @version = version - @repository = repository - end - - def generate_script - super + [ - init_command, - repository_command, - repository_update_command, - upgrade_command - ].compact.join("\n") - end - - private - - def upgrade_command - command = ['helm', 'upgrade', name, chart] + - reuse_values_flag + - version_flag + - namespace_flag + - value_flag - - command.shelljoin - end - - def reuse_values_flag - ['--reuse-values'] - end - - def value_flag - ['-f', "/data/helm/#{name}/config/values.yaml"] - end - - def namespace_flag - ['--namespace', Gitlab::Kubernetes::Helm::NAMESPACE] - end - - def version_flag - ['--version', version] - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb index 75484f80070..9d0207e6b1f 100644 --- a/lib/gitlab/kubernetes/helm/pod.rb +++ b/lib/gitlab/kubernetes/helm/pod.rb @@ -27,7 +27,7 @@ module Gitlab def container_specification { name: 'helm', - image: "registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/#{Gitlab::Kubernetes::Helm::HELM_VERSION}-kube-#{Gitlab::Kubernetes::Helm::KUBECTL_VERSION}", + image: "registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/#{command.class::HELM_VERSION}-kube-#{Gitlab::Kubernetes::Helm::KUBECTL_VERSION}-alpine-3.12", env: generate_pod_env(command), command: %w(/bin/sh), args: %w(-c $(COMMAND_SCRIPT)) @@ -50,11 +50,10 @@ module Gitlab end def generate_pod_env(command) - { - HELM_VERSION: Gitlab::Kubernetes::Helm::HELM_VERSION, - TILLER_NAMESPACE: namespace_name, + command.env.merge( + HELM_VERSION: command.class::HELM_VERSION, COMMAND_SCRIPT: command.generate_script - }.map { |key, value| { name: key, value: value } } + ).map { |key, value| { name: key, value: value } } end def volumes_specification diff --git a/lib/gitlab/kubernetes/helm/reset_command.rb b/lib/gitlab/kubernetes/helm/reset_command.rb deleted file mode 100644 index f1f7938039c..00000000000 --- a/lib/gitlab/kubernetes/helm/reset_command.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -module Gitlab - module Kubernetes - module Helm - class ResetCommand < BaseCommand - include ClientCommand - - def generate_script - super + [ - reset_helm_command, - delete_tiller_replicaset, - delete_tiller_clusterrolebinding - ].join("\n") - end - - def pod_name - "uninstall-#{name}" - end - - private - - # This method can be delete once we upgrade Helm to > 12.13.0 - # https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/27096#note_159695900 - # - # Tracking this method to be removed here: - # https://gitlab.com/gitlab-org/gitlab-foss/issues/52791#note_199374155 - def delete_tiller_replicaset - delete_args = %w[replicaset -n gitlab-managed-apps -l name=tiller] - - Gitlab::Kubernetes::KubectlCmd.delete(*delete_args) - end - - def delete_tiller_clusterrolebinding - delete_args = %w[clusterrolebinding tiller-admin] - - Gitlab::Kubernetes::KubectlCmd.delete(*delete_args) - end - - def reset_helm_command - command = %w[helm reset] + optional_tls_flags - - command.shelljoin - end - end - end - end -end diff --git a/lib/gitlab/kubernetes/helm/v2/base_command.rb b/lib/gitlab/kubernetes/helm/v2/base_command.rb new file mode 100644 index 00000000000..931c2248310 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/base_command.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V2 + class BaseCommand + attr_reader :name, :files + + HELM_VERSION = '2.16.9' + + def initialize(rbac:, name:, files:) + @rbac = rbac + @name = name + @files = files + end + + def env + { TILLER_NAMESPACE: namespace } + end + + def rbac? + @rbac + end + + def pod_resource + pod_service_account_name = rbac? ? service_account_name : nil + + Gitlab::Kubernetes::Helm::Pod.new(self, namespace, service_account_name: pod_service_account_name).generate + end + + def generate_script + <<~HEREDOC + set -xeo pipefail + HEREDOC + end + + def pod_name + "install-#{name}" + end + + def config_map_resource + Gitlab::Kubernetes::ConfigMap.new(name, files).generate + end + + def service_account_resource + return unless rbac? + + Gitlab::Kubernetes::ServiceAccount.new(service_account_name, namespace).generate + end + + def cluster_role_binding_resource + return unless rbac? + + subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: namespace }] + + Gitlab::Kubernetes::ClusterRoleBinding.new( + cluster_role_binding_name, + cluster_role_name, + subjects + ).generate + end + + def file_names + files.keys + end + + private + + def files_dir + "/data/helm/#{name}/config" + end + + def namespace + Gitlab::Kubernetes::Helm::NAMESPACE + end + + def service_account_name + Gitlab::Kubernetes::Helm::SERVICE_ACCOUNT + end + + def cluster_role_binding_name + Gitlab::Kubernetes::Helm::CLUSTER_ROLE_BINDING + end + + def cluster_role_name + Gitlab::Kubernetes::Helm::CLUSTER_ROLE + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/certificate.rb b/lib/gitlab/kubernetes/helm/v2/certificate.rb new file mode 100644 index 00000000000..f603ff44ef3 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/certificate.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true +module Gitlab + module Kubernetes + module Helm + module V2 + class Certificate + INFINITE_EXPIRY = 1000.years + SHORT_EXPIRY = 30.minutes + + attr_reader :key, :cert + + def key_string + @key.to_s + end + + def cert_string + @cert.to_pem + end + + def self.from_strings(key_string, cert_string) + key = OpenSSL::PKey::RSA.new(key_string) + cert = OpenSSL::X509::Certificate.new(cert_string) + new(key, cert) + end + + def self.generate_root + _issue(signed_by: nil, expires_in: INFINITE_EXPIRY, certificate_authority: true) + end + + def issue(expires_in: SHORT_EXPIRY) + self.class._issue(signed_by: self, expires_in: expires_in, certificate_authority: false) + end + + private + + def self._issue(signed_by:, expires_in:, certificate_authority:) + key = OpenSSL::PKey::RSA.new(4096) + public_key = key.public_key + + subject = OpenSSL::X509::Name.parse("/C=US") + + cert = OpenSSL::X509::Certificate.new + cert.subject = subject + + cert.issuer = signed_by&.cert&.subject || subject + + cert.not_before = Time.now.utc + cert.not_after = expires_in.from_now.utc + cert.public_key = public_key + cert.serial = 0x0 + cert.version = 2 + + if certificate_authority + extension_factory = OpenSSL::X509::ExtensionFactory.new + extension_factory.subject_certificate = cert + extension_factory.issuer_certificate = cert + cert.add_extension(extension_factory.create_extension('subjectKeyIdentifier', 'hash')) + cert.add_extension(extension_factory.create_extension('basicConstraints', 'CA:TRUE', true)) + cert.add_extension(extension_factory.create_extension('keyUsage', 'cRLSign,keyCertSign', true)) + end + + cert.sign(signed_by&.key || key, OpenSSL::Digest::SHA256.new) + + new(key, cert) + end + + def initialize(key, cert) + @key = key + @cert = cert + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/client_command.rb b/lib/gitlab/kubernetes/helm/v2/client_command.rb new file mode 100644 index 00000000000..88693a28d6c --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/client_command.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V2 + module ClientCommand + def init_command + <<~SHELL.chomp + export HELM_HOST="localhost:44134" + tiller -listen ${HELM_HOST} -alsologtostderr & + helm init --client-only + SHELL + end + + def repository_command + ['helm', 'repo', 'add', name, repository].shelljoin if repository + end + + private + + def repository_update_command + 'helm repo update' + end + + def optional_tls_flags + return [] unless files.key?(:'ca.pem') + + [ + '--tls', + '--tls-ca-cert', "#{files_dir}/ca.pem", + '--tls-cert', "#{files_dir}/cert.pem", + '--tls-key', "#{files_dir}/key.pem" + ] + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/delete_command.rb b/lib/gitlab/kubernetes/helm/v2/delete_command.rb new file mode 100644 index 00000000000..4d52fc1398f --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/delete_command.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V2 + class DeleteCommand < BaseCommand + include ClientCommand + + attr_reader :predelete, :postdelete + + def initialize(predelete: nil, postdelete: nil, **args) + super(**args) + @predelete = predelete + @postdelete = postdelete + end + + def generate_script + super + [ + init_command, + predelete, + delete_command, + postdelete + ].compact.join("\n") + end + + def pod_name + "uninstall-#{name}" + end + + def delete_command + ['helm', 'delete', '--purge', name].shelljoin + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/init_command.rb b/lib/gitlab/kubernetes/helm/v2/init_command.rb new file mode 100644 index 00000000000..f8b52feb5b6 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/init_command.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V2 + class InitCommand < BaseCommand + def generate_script + super + [ + init_helm_command + ].join("\n") + end + + private + + def init_helm_command + command = %w[helm init] + init_command_flags + + command.shelljoin + end + + def init_command_flags + tls_flags + optional_service_account_flag + end + + def tls_flags + [ + '--tiller-tls', + '--tiller-tls-verify', + '--tls-ca-cert', "#{files_dir}/ca.pem", + '--tiller-tls-cert', "#{files_dir}/cert.pem", + '--tiller-tls-key', "#{files_dir}/key.pem" + ] + end + + def optional_service_account_flag + return [] unless rbac? + + ['--service-account', service_account_name] + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/install_command.rb b/lib/gitlab/kubernetes/helm/v2/install_command.rb new file mode 100644 index 00000000000..10e16723e45 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/install_command.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V2 + class InstallCommand < BaseCommand + include ClientCommand + + attr_reader :chart, :repository, :preinstall, :postinstall + attr_accessor :version + + def initialize(chart:, version: nil, repository: nil, preinstall: nil, postinstall: nil, **args) + super(**args) + @chart = chart + @version = version + @repository = repository + @preinstall = preinstall + @postinstall = postinstall + end + + def generate_script + super + [ + init_command, + repository_command, + repository_update_command, + preinstall, + install_command, + postinstall + ].compact.join("\n") + end + + private + + # Uses `helm upgrade --install` which means we can use this for both + # installation and uprade of applications + def install_command + command = ['helm', 'upgrade', name, chart] + + install_flag + + rollback_support_flag + + reset_values_flag + + optional_version_flag + + rbac_create_flag + + namespace_flag + + value_flag + + command.shelljoin + end + + def install_flag + ['--install'] + end + + def reset_values_flag + ['--reset-values'] + end + + def value_flag + ['-f', "/data/helm/#{name}/config/values.yaml"] + end + + def namespace_flag + ['--namespace', Gitlab::Kubernetes::Helm::NAMESPACE] + end + + def rbac_create_flag + if rbac? + %w[--set rbac.create=true,rbac.enabled=true] + else + %w[--set rbac.create=false,rbac.enabled=false] + end + end + + def optional_version_flag + return [] unless version + + ['--version', version] + end + + def rollback_support_flag + ['--atomic', '--cleanup-on-fail'] + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/patch_command.rb b/lib/gitlab/kubernetes/helm/v2/patch_command.rb new file mode 100644 index 00000000000..2855e6444b1 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/patch_command.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +# PatchCommand is for updating values in installed charts without overwriting +# existing values. +module Gitlab + module Kubernetes + module Helm + module V2 + class PatchCommand < BaseCommand + include ClientCommand + + attr_reader :chart, :repository + attr_accessor :version + + def initialize(chart:, version:, repository: nil, **args) + super(**args) + + # version is mandatory to prevent chart mismatches + # we do not want our values interpreted in the context of the wrong version + raise ArgumentError, 'version is required' if version.blank? + + @chart = chart + @version = version + @repository = repository + end + + def generate_script + super + [ + init_command, + repository_command, + repository_update_command, + upgrade_command + ].compact.join("\n") + end + + private + + def upgrade_command + command = ['helm', 'upgrade', name, chart] + + reuse_values_flag + + version_flag + + namespace_flag + + value_flag + + command.shelljoin + end + + def reuse_values_flag + ['--reuse-values'] + end + + def value_flag + ['-f', "/data/helm/#{name}/config/values.yaml"] + end + + def namespace_flag + ['--namespace', Gitlab::Kubernetes::Helm::NAMESPACE] + end + + def version_flag + ['--version', version] + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v2/reset_command.rb b/lib/gitlab/kubernetes/helm/v2/reset_command.rb new file mode 100644 index 00000000000..172a0884c49 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v2/reset_command.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V2 + class ResetCommand < BaseCommand + include ClientCommand + + def generate_script + super + [ + reset_helm_command, + delete_tiller_replicaset, + delete_tiller_clusterrolebinding + ].join("\n") + end + + def pod_name + "uninstall-#{name}" + end + + private + + # This method can be delete once we upgrade Helm to > 12.13.0 + # https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/27096#note_159695900 + # + # Tracking this method to be removed here: + # https://gitlab.com/gitlab-org/gitlab-foss/issues/52791#note_199374155 + def delete_tiller_replicaset + delete_args = %w[replicaset -n gitlab-managed-apps -l name=tiller] + + Gitlab::Kubernetes::KubectlCmd.delete(*delete_args) + end + + def delete_tiller_clusterrolebinding + delete_args = %w[clusterrolebinding tiller-admin] + + Gitlab::Kubernetes::KubectlCmd.delete(*delete_args) + end + + def reset_helm_command + command = %w[helm reset] + optional_tls_flags + + command.shelljoin + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v3/base_command.rb b/lib/gitlab/kubernetes/helm/v3/base_command.rb new file mode 100644 index 00000000000..ca1bf5462f0 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v3/base_command.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V3 + class BaseCommand + attr_reader :name, :files + + HELM_VERSION = '3.2.4' + + def initialize(rbac:, name:, files:) + @rbac = rbac + @name = name + @files = files + end + + def env + {} + end + + def rbac? + @rbac + end + + def pod_resource + pod_service_account_name = rbac? ? service_account_name : nil + + Gitlab::Kubernetes::Helm::Pod.new(self, namespace, service_account_name: pod_service_account_name).generate + end + + def generate_script + <<~HEREDOC + set -xeo pipefail + HEREDOC + end + + def pod_name + "install-#{name}" + end + + def config_map_resource + Gitlab::Kubernetes::ConfigMap.new(name, files).generate + end + + def service_account_resource + return unless rbac? + + Gitlab::Kubernetes::ServiceAccount.new(service_account_name, namespace).generate + end + + def cluster_role_binding_resource + return unless rbac? + + subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: namespace }] + + Gitlab::Kubernetes::ClusterRoleBinding.new( + cluster_role_binding_name, + cluster_role_name, + subjects + ).generate + end + + def file_names + files.keys + end + + def repository_command + ['helm', 'repo', 'add', name, repository].shelljoin if repository + end + + private + + def repository_update_command + 'helm repo update' + end + + def namespace_flag + ['--namespace', Gitlab::Kubernetes::Helm::NAMESPACE] + end + + def namespace + Gitlab::Kubernetes::Helm::NAMESPACE + end + + def service_account_name + Gitlab::Kubernetes::Helm::SERVICE_ACCOUNT + end + + def cluster_role_binding_name + Gitlab::Kubernetes::Helm::CLUSTER_ROLE_BINDING + end + + def cluster_role_name + Gitlab::Kubernetes::Helm::CLUSTER_ROLE + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v3/delete_command.rb b/lib/gitlab/kubernetes/helm/v3/delete_command.rb new file mode 100644 index 00000000000..f628e852f54 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v3/delete_command.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V3 + class DeleteCommand < BaseCommand + attr_reader :predelete, :postdelete + + def initialize(predelete: nil, postdelete: nil, **args) + super(**args) + @predelete = predelete + @postdelete = postdelete + end + + def generate_script + super + [ + predelete, + delete_command, + postdelete + ].compact.join("\n") + end + + def pod_name + "uninstall-#{name}" + end + + def delete_command + ['helm', 'uninstall', name, *namespace_flag].shelljoin + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v3/install_command.rb b/lib/gitlab/kubernetes/helm/v3/install_command.rb new file mode 100644 index 00000000000..20d17f49115 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v3/install_command.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module Gitlab + module Kubernetes + module Helm + module V3 + class InstallCommand < BaseCommand + attr_reader :chart, :repository, :preinstall, :postinstall + attr_accessor :version + + def initialize(chart:, version: nil, repository: nil, preinstall: nil, postinstall: nil, **args) + super(**args) + @chart = chart + @version = version + @repository = repository + @preinstall = preinstall + @postinstall = postinstall + end + + def generate_script + super + [ + repository_command, + repository_update_command, + preinstall, + install_command, + postinstall + ].compact.join("\n") + end + + private + + # Uses `helm upgrade --install` which means we can use this for both + # installation and uprade of applications + def install_command + command = ['helm', 'upgrade', name, chart] + + install_flag + + rollback_support_flag + + reset_values_flag + + optional_version_flag + + rbac_create_flag + + namespace_flag + + value_flag + + command.shelljoin + end + + def install_flag + ['--install'] + end + + def reset_values_flag + ['--reset-values'] + end + + def value_flag + ['-f', "/data/helm/#{name}/config/values.yaml"] + end + + def rbac_create_flag + if rbac? + %w[--set rbac.create=true,rbac.enabled=true] + else + %w[--set rbac.create=false,rbac.enabled=false] + end + end + + def optional_version_flag + return [] unless version + + ['--version', version] + end + + def rollback_support_flag + ['--atomic', '--cleanup-on-fail'] + end + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/v3/patch_command.rb b/lib/gitlab/kubernetes/helm/v3/patch_command.rb new file mode 100644 index 00000000000..00f340591e7 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/v3/patch_command.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +# PatchCommand is for updating values in installed charts without overwriting +# existing values. +module Gitlab + module Kubernetes + module Helm + module V3 + class PatchCommand < BaseCommand + attr_reader :chart, :repository + attr_accessor :version + + def initialize(chart:, version:, repository: nil, **args) + super(**args) + + # version is mandatory to prevent chart mismatches + # we do not want our values interpreted in the context of the wrong version + raise ArgumentError, 'version is required' if version.blank? + + @chart = chart + @version = version + @repository = repository + end + + def generate_script + super + [ + repository_command, + repository_update_command, + upgrade_command + ].compact.join("\n") + end + + private + + def upgrade_command + command = ['helm', 'upgrade', name, chart] + + reuse_values_flag + + version_flag + + namespace_flag + + value_flag + + command.shelljoin + end + + def reuse_values_flag + ['--reuse-values'] + end + + def value_flag + ['-f', "/data/helm/#{name}/config/values.yaml"] + end + + def version_flag + ['--version', version] + end + end + end + end + end +end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 01886a4edcb..d283d5caf08 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -18511,6 +18511,9 @@ msgstr "" msgid "Notes|This comment has changed since you started editing, please review the %{open_link}updated comment%{close_link} to ensure information is not lost" msgstr "" +msgid "Notes|You're only seeing %{boldStart}other activity%{boldEnd} in the feed. To add a comment, switch to one of the following options." +msgstr "" + msgid "Nothing found…" msgstr "" @@ -30920,9 +30923,6 @@ msgstr "" msgid "You're not allowed to make changes to this project directly. A fork of this project is being created that you can make changes in, so you can submit a merge request." msgstr "" -msgid "You're only seeing %{startTag}other activity%{endTag} in the feed. To add a comment, switch to one of the following options." -msgstr "" - msgid "You're receiving this email because of your account on %{host}." msgstr "" diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index 46aa640780b..01df5cc677d 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -5,7 +5,7 @@ FactoryBot.define do cluster factory: %i(cluster provided_by_gcp) before(:create) do - allow(Gitlab::Kubernetes::Helm::Certificate).to receive(:generate_root) + allow(Gitlab::Kubernetes::Helm::V2::Certificate).to receive(:generate_root) .and_return( double( key_string: File.read(Rails.root.join('spec/fixtures/clusters/sample_key.key')), @@ -15,7 +15,7 @@ FactoryBot.define do end after(:create) do - allow(Gitlab::Kubernetes::Helm::Certificate).to receive(:generate_root).and_call_original + allow(Gitlab::Kubernetes::Helm::V2::Certificate).to receive(:generate_root).and_call_original end trait :not_installable do diff --git a/spec/fixtures/api/schemas/public_api/v4/release.json b/spec/fixtures/api/schemas/public_api/v4/release.json index 02e23d2732d..69ac383b7fd 100644 --- a/spec/fixtures/api/schemas/public_api/v4/release.json +++ b/spec/fixtures/api/schemas/public_api/v4/release.json @@ -21,7 +21,6 @@ }, "commit_path": { "type": "string" }, "tag_path": { "type": "string" }, - "name": { "type": "string" }, "evidences": { "type": "array", "items": { "$ref": "release/evidence.json" } @@ -42,11 +41,8 @@ "additionalProperties": false }, "_links": { - "required": ["merge_requests_url", "issues_url"], "properties": { - "merge_requests_url": { "type": "string" }, - "issues_url": { "type": "string" }, - "edit_url": { "type": "string"} + "edit_url": { "type": "string" } } } }, diff --git a/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json b/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json index 1a1e92ac778..058b7b4b4ed 100644 --- a/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json +++ b/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json @@ -26,11 +26,7 @@ "additionalProperties": false }, "_links": { - "required": ["merge_requests_url", "issues_url"], - "properties": { - "merge_requests_url": { "type": "string" }, - "issues_url": { "type": "string" } - } + "properties": {} } }, "additionalProperties": false diff --git a/spec/frontend/notes/components/discussion_filter_note_spec.js b/spec/frontend/notes/components/discussion_filter_note_spec.js index 4701108d315..d35f8f7c28d 100644 --- a/spec/frontend/notes/components/discussion_filter_note_spec.js +++ b/spec/frontend/notes/components/discussion_filter_note_spec.js @@ -1,4 +1,5 @@ import { shallowMount } from '@vue/test-utils'; +import { GlButton, GlSprintf } from '@gitlab/ui'; import DiscussionFilterNote from '~/notes/components/discussion_filter_note.vue'; import eventHub from '~/notes/event_hub'; @@ -6,7 +7,11 @@ describe('DiscussionFilterNote component', () => { let wrapper; const createComponent = () => { - wrapper = shallowMount(DiscussionFilterNote); + wrapper = shallowMount(DiscussionFilterNote, { + stubs: { + GlSprintf, + }, + }); }; beforeEach(() => { @@ -19,21 +24,27 @@ describe('DiscussionFilterNote component', () => { }); it('timelineContent renders a string containing instruction for switching feed type', () => { - expect(wrapper.find({ ref: 'timelineContent' }).html()).toBe( - "<div>You're only seeing <b>other activity</b> in the feed. To add a comment, switch to one of the following options.</div>", + expect(wrapper.find('[data-testid="discussion-filter-timeline-content"]').html()).toBe( + '<div data-testid="discussion-filter-timeline-content">You\'re only seeing <b>other activity</b> in the feed. To add a comment, switch to one of the following options.</div>', ); }); it('emits `dropdownSelect` event with 0 parameter on clicking Show all activity button', () => { jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); - wrapper.find({ ref: 'showAllActivity' }).vm.$emit('click'); + wrapper + .findAll(GlButton) + .at(0) + .vm.$emit('click'); expect(eventHub.$emit).toHaveBeenCalledWith('dropdownSelect', 0); }); it('emits `dropdownSelect` event with 1 parameter on clicking Show comments only button', () => { jest.spyOn(eventHub, '$emit').mockImplementation(() => {}); - wrapper.find({ ref: 'showComments' }).vm.$emit('click'); + wrapper + .findAll(GlButton) + .at(1) + .vm.$emit('click'); expect(eventHub.$emit).toHaveBeenCalledWith('dropdownSelect', 1); }); diff --git a/spec/graphql/types/release_links_type_spec.rb b/spec/graphql/types/release_links_type_spec.rb index d3494e0e86c..38c38d58baa 100644 --- a/spec/graphql/types/release_links_type_spec.rb +++ b/spec/graphql/types/release_links_type_spec.rb @@ -14,8 +14,6 @@ RSpec.describe GitlabSchema.types['ReleaseLinks'] do openedIssuesUrl closedIssuesUrl editUrl - mergeRequestsUrl - issuesUrl ] expect(described_class).to include_graphql_fields(*expected_fields) diff --git a/spec/lib/gitlab/import_export/importer_spec.rb b/spec/lib/gitlab/import_export/importer_spec.rb index 7c10011273a..0db038785d3 100644 --- a/spec/lib/gitlab/import_export/importer_spec.rb +++ b/spec/lib/gitlab/import_export/importer_spec.rb @@ -65,10 +65,22 @@ RSpec.describe Gitlab::ImportExport::Importer do end end - it 'restores the ProjectTree' do - expect(Gitlab::ImportExport::Project::TreeRestorer).to receive(:new).and_call_original + context 'with sample_data_template' do + it 'initializes the Sample::TreeRestorer' do + project.create_or_update_import_data(data: { sample_data: true }) - importer.execute + expect(Gitlab::ImportExport::Project::Sample::TreeRestorer).to receive(:new).and_call_original + + importer.execute + end + end + + context 'without sample_data_template' do + it 'initializes the ProjectTree' do + expect(Gitlab::ImportExport::Project::TreeRestorer).to receive(:new).and_call_original + + importer.execute + end end it 'removes the import file' do diff --git a/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb new file mode 100644 index 00000000000..86d5f2402f8 --- /dev/null +++ b/spec/lib/gitlab/import_export/project/sample/relation_factory_spec.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::ImportExport::Project::Sample::RelationFactory do + let(:group) { create(:group) } + let(:project) { create(:project, :repository, group: group) } + let(:members_mapper) { double('members_mapper').as_null_object } + let(:admin) { create(:admin) } + let(:importer_user) { admin } + let(:excluded_keys) { [] } + let(:date_calculator) { instance_double(Gitlab::ImportExport::Project::Sample::DateCalculator) } + let(:original_project_id) { 8 } + let(:start_date) { Time.current - 30.days } + let(:due_date) { Time.current - 20.days } + let(:created_object) do + described_class.create( # rubocop:disable Rails/SaveBang + relation_sym: relation_sym, + relation_hash: relation_hash, + object_builder: Gitlab::ImportExport::Project::ObjectBuilder, + members_mapper: members_mapper, + user: importer_user, + importable: project, + excluded_keys: excluded_keys, + date_calculator: date_calculator + ) + end + + context 'issue object' do + let(:relation_sym) { :issues } + let(:id) { 999 } + + let(:relation_hash) do + { + 'id' => id, + 'title' => 'Necessitatibus magnam qui at velit consequatur perspiciatis.', + 'project_id' => original_project_id, + 'created_at' => '2016-08-12T09:41:03.462Z', + 'updated_at' => '2016-08-12T09:41:03.462Z', + 'description' => 'Molestiae corporis magnam et fugit aliquid nulla quia.', + 'state' => 'closed', + 'position' => 0, + 'confidential' => false, + 'due_date' => due_date + } + end + + before do + allow(date_calculator).to receive(:closest_date_to_average) { Time.current - 10.days } + allow(date_calculator).to receive(:calculate_by_closest_date_to_average) + end + + it 'correctly updated due date', :aggregate_failures do + expect(date_calculator).to receive(:calculate_by_closest_date_to_average) + .with(relation_hash['due_date']).and_return(due_date - 10.days) + + expect(created_object.due_date).to eq((due_date - 10.days).to_date) + end + end + + context 'milestone object' do + let(:relation_sym) { :milestones } + let(:id) { 1001 } + + let(:relation_hash) do + { + 'id' => id, + 'title' => 'v3.0', + 'project_id' => original_project_id, + 'created_at' => '2016-08-12T09:41:03.462Z', + 'updated_at' => '2016-08-12T09:41:03.462Z', + 'description' => 'Rerum at autem exercitationem ea voluptates harum quam placeat.', + 'state' => 'closed', + 'start_date' => start_date, + 'due_date' => due_date + } + end + + before do + allow(date_calculator).to receive(:closest_date_to_average).twice { Time.current - 10.days } + allow(date_calculator).to receive(:calculate_by_closest_date_to_average).twice + end + + it 'correctly updated due date', :aggregate_failures do + expect(date_calculator).to receive(:calculate_by_closest_date_to_average) + .with(relation_hash['due_date']).and_return(due_date - 10.days) + + expect(created_object.due_date).to eq((due_date - 10.days).to_date) + end + + it 'correctly updated start date', :aggregate_failures do + expect(date_calculator).to receive(:calculate_by_closest_date_to_average) + .with(relation_hash['start_date']).and_return(start_date - 20.days) + + expect(created_object.start_date).to eq((start_date - 20.days).to_date) + end + end + + context 'milestone object' do + let(:relation_sym) { :milestones } + let(:id) { 1001 } + + let(:relation_hash) do + { + 'id' => id, + 'title' => 'v3.0', + 'project_id' => original_project_id, + 'created_at' => '2016-08-12T09:41:03.462Z', + 'updated_at' => '2016-08-12T09:41:03.462Z', + 'description' => 'Rerum at autem exercitationem ea voluptates harum quam placeat.', + 'state' => 'closed', + 'start_date' => start_date, + 'due_date' => due_date + } + end + + before do + allow(date_calculator).to receive(:closest_date_to_average).twice { Time.current - 10.days } + allow(date_calculator).to receive(:calculate_by_closest_date_to_average).twice + end + + it 'correctly updated due date', :aggregate_failures do + expect(date_calculator).to receive(:calculate_by_closest_date_to_average) + .with(relation_hash['due_date']).and_return(due_date - 10.days) + + expect(created_object.due_date).to eq((due_date - 10.days).to_date) + end + + it 'correctly updated start date', :aggregate_failures do + expect(date_calculator).to receive(:calculate_by_closest_date_to_average) + .with(relation_hash['start_date']).and_return(start_date - 20.days) + + expect(created_object.start_date).to eq((start_date - 20.days).to_date) + end + end + + context 'hook object' do + let(:relation_sym) { :hooks } + let(:id) { 999 } + let(:service_id) { 99 } + let(:token) { 'secret' } + + let(:relation_hash) do + { + 'id' => id, + 'url' => 'https://example.json', + 'project_id' => original_project_id, + 'created_at' => '2016-08-12T09:41:03.462Z', + 'updated_at' => '2016-08-12T09:41:03.462Z', + 'service_id' => service_id, + 'push_events' => true, + 'issues_events' => false, + 'confidential_issues_events' => false, + 'merge_requests_events' => true, + 'tag_push_events' => false, + 'note_events' => true, + 'enable_ssl_verification' => true, + 'job_events' => false, + 'wiki_page_events' => true, + 'token' => token + } + end + + it 'does not calculate the closest date to average' do + expect(date_calculator).not_to receive(:calculate_by_closest_date_to_average) + end + end +end diff --git a/spec/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/sample/relation_tree_restorer_spec.rb index f173345a4c6..f87f79d4462 100644 --- a/spec/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/sample/relation_tree_restorer_spec.rb @@ -9,7 +9,7 @@ require 'spec_helper' -RSpec.describe Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRestorer do +RSpec.describe Gitlab::ImportExport::Project::Sample::RelationTreeRestorer do include_context 'relation tree restorer shared context' let(:sample_data_relation_tree_restorer) do @@ -74,13 +74,26 @@ RSpec.describe Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRest let(:importable_name) { 'project' } let(:importable_path) { 'project' } let(:object_builder) { Gitlab::ImportExport::Project::ObjectBuilder } - let(:relation_factory) { Gitlab::ImportExport::Project::RelationFactory } + let(:relation_factory) { Gitlab::ImportExport::Project::Sample::RelationFactory } let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) } + let(:path) { 'spec/fixtures/lib/gitlab/import_export/sample_data/tree' } + let(:relation_reader) { Gitlab::ImportExport::JSON::NdjsonReader.new(path) } - context 'using ndjson reader' do - let(:path) { 'spec/fixtures/lib/gitlab/import_export/sample_data/tree' } - let(:relation_reader) { Gitlab::ImportExport::JSON::NdjsonReader.new(path) } + it 'initializes relation_factory with date_calculator as parameter' do + expect(Gitlab::ImportExport::Project::Sample::RelationFactory).to receive(:create).with(hash_including(:date_calculator)).at_least(:once).times + + subject + end + + context 'when relation tree restorer is initialized' do + it 'initializes date calculator with due dates' do + expect(Gitlab::ImportExport::Project::Sample::DateCalculator).to receive(:new).with(Array) + sample_data_relation_tree_restorer + end + end + + context 'using ndjson reader' do it_behaves_like 'import project successfully' end end diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb index c05968c9a85..f75494aa7c7 100644 --- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb @@ -1040,41 +1040,6 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do it_behaves_like 'project tree restorer work properly', :legacy_reader, true it_behaves_like 'project tree restorer work properly', :ndjson_reader, true - - context 'Sample Data JSON' do - let(:user) { create(:user) } - let!(:project) { create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') } - let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) } - - before do - setup_import_export_config('sample_data') - setup_reader(:ndjson_reader) - end - - context 'with sample_data_template' do - before do - allow(project).to receive_message_chain(:import_data, :data, :dig).with('sample_data') { true } - end - - it 'initialize SampleDataRelationTreeRestorer' do - expect_next_instance_of(Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRestorer) do |restorer| - expect(restorer).to receive(:restore).and_return(true) - end - - expect(project_tree_restorer.restore).to eq(true) - end - end - - context 'without sample_data_template' do - it 'initialize RelationTreeRestorer' do - expect_next_instance_of(Gitlab::ImportExport::RelationTreeRestorer) do |restorer| - expect(restorer).to receive(:restore).and_return(true) - end - - expect(project_tree_restorer.restore).to eq(true) - end - end - end end context 'disable ndjson import' do diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb index bcc95bdbf2b..e022f5bd912 100644 --- a/spec/lib/gitlab/kubernetes/helm/api_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Gitlab::Kubernetes::Helm::API do let(:files) { {} } let(:command) do - Gitlab::Kubernetes::Helm::InstallCommand.new( + Gitlab::Kubernetes::Helm::V2::InstallCommand.new( name: application_name, chart: 'chart-name', rbac: rbac, @@ -142,7 +142,7 @@ RSpec.describe Gitlab::Kubernetes::Helm::API do end context 'with a service account' do - let(:command) { Gitlab::Kubernetes::Helm::InitCommand.new(name: application_name, files: files, rbac: rbac) } + let(:command) { Gitlab::Kubernetes::Helm::V2::InitCommand.new(name: application_name, files: files, rbac: rbac) } context 'rbac-enabled cluster' do let(:rbac) { true } diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb index 54e3289dd25..6d97790fc8b 100644 --- a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb @@ -4,75 +4,84 @@ require 'spec_helper' RSpec.describe Gitlab::Kubernetes::Helm::Pod do describe '#generate' do - let(:app) { create(:clusters_applications_prometheus) } - let(:command) { app.install_command } - let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE } - let(:service_account_name) { nil } + using RSpec::Parameterized::TableSyntax - subject { described_class.new(command, namespace, service_account_name: service_account_name) } + where(:helm_major_version, :expected_helm_version, :expected_command_env) do + 2 | '2.16.9' | [:TILLER_NAMESPACE] + 3 | '3.2.4' | nil + end - context 'with a command' do - it 'generates a Kubeclient::Resource' do - expect(subject.generate).to be_a_kind_of(Kubeclient::Resource) - end + with_them do + let(:cluster) { create(:cluster, helm_major_version: helm_major_version) } + let(:app) { create(:clusters_applications_prometheus, cluster: cluster) } + let(:command) { app.install_command } + let(:namespace) { Gitlab::Kubernetes::Helm::NAMESPACE } + let(:service_account_name) { nil } - it 'generates the appropriate metadata' do - metadata = subject.generate.metadata - expect(metadata.name).to eq("install-#{app.name}") - expect(metadata.namespace).to eq('gitlab-managed-apps') - expect(metadata.labels['gitlab.org/action']).to eq('install') - expect(metadata.labels['gitlab.org/application']).to eq(app.name) - end + subject { described_class.new(command, namespace, service_account_name: service_account_name) } - it 'generates a container spec' do - spec = subject.generate.spec - expect(spec.containers.count).to eq(1) - end + context 'with a command' do + it 'generates a Kubeclient::Resource' do + expect(subject.generate).to be_a_kind_of(Kubeclient::Resource) + end - it 'generates the appropriate specifications for the container' do - container = subject.generate.spec.containers.first - expect(container.name).to eq('helm') - expect(container.image).to eq('registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/2.16.9-kube-1.13.12') - expect(container.env.count).to eq(3) - expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT]) - expect(container.command).to match_array(["/bin/sh"]) - expect(container.args).to match_array(["-c", "$(COMMAND_SCRIPT)"]) - end + it 'generates the appropriate metadata' do + metadata = subject.generate.metadata + expect(metadata.name).to eq("install-#{app.name}") + expect(metadata.namespace).to eq('gitlab-managed-apps') + expect(metadata.labels['gitlab.org/action']).to eq('install') + expect(metadata.labels['gitlab.org/application']).to eq(app.name) + end - it 'includes a never restart policy' do - spec = subject.generate.spec - expect(spec.restartPolicy).to eq('Never') - end + it 'generates a container spec' do + spec = subject.generate.spec + expect(spec.containers.count).to eq(1) + end - it 'includes volumes for the container' do - container = subject.generate.spec.containers.first - expect(container.volumeMounts.first['name']).to eq('configuration-volume') - expect(container.volumeMounts.first['mountPath']).to eq("/data/helm/#{app.name}/config") - end + it 'generates the appropriate specifications for the container' do + container = subject.generate.spec.containers.first + expect(container.name).to eq('helm') + expect(container.image).to eq("registry.gitlab.com/gitlab-org/cluster-integration/helm-install-image/releases/#{expected_helm_version}-kube-1.13.12-alpine-3.12") + expect(container.env.map(&:name)).to include(:HELM_VERSION, :COMMAND_SCRIPT, *expected_command_env) + expect(container.command).to match_array(["/bin/sh"]) + expect(container.args).to match_array(["-c", "$(COMMAND_SCRIPT)"]) + end - it 'includes a volume inside the specification' do - spec = subject.generate.spec - expect(spec.volumes.first['name']).to eq('configuration-volume') - end + it 'includes a never restart policy' do + spec = subject.generate.spec + expect(spec.restartPolicy).to eq('Never') + end - it 'mounts configMap specification in the volume' do - volume = subject.generate.spec.volumes.first - expect(volume.configMap['name']).to eq("values-content-configuration-#{app.name}") - expect(volume.configMap['items'].first['key']).to eq(:'values.yaml') - expect(volume.configMap['items'].first['path']).to eq(:'values.yaml') - end + it 'includes volumes for the container' do + container = subject.generate.spec.containers.first + expect(container.volumeMounts.first['name']).to eq('configuration-volume') + expect(container.volumeMounts.first['mountPath']).to eq("/data/helm/#{app.name}/config") + end - it 'has no serviceAccountName' do - spec = subject.generate.spec - expect(spec.serviceAccountName).to be_nil - end + it 'includes a volume inside the specification' do + spec = subject.generate.spec + expect(spec.volumes.first['name']).to eq('configuration-volume') + end - context 'with a service_account_name' do - let(:service_account_name) { 'sa' } + it 'mounts configMap specification in the volume' do + volume = subject.generate.spec.volumes.first + expect(volume.configMap['name']).to eq("values-content-configuration-#{app.name}") + expect(volume.configMap['items'].first['key']).to eq(:'values.yaml') + expect(volume.configMap['items'].first['path']).to eq(:'values.yaml') + end - it 'uses the serviceAccountName provided' do + it 'has no serviceAccountName' do spec = subject.generate.spec - expect(spec.serviceAccountName).to eq(service_account_name) + expect(spec.serviceAccountName).to be_nil + end + + context 'with a service_account_name' do + let(:service_account_name) { 'sa' } + + it 'uses the serviceAccountName provided' do + spec = subject.generate.spec + expect(spec.serviceAccountName).to eq(service_account_name) + end end end end diff --git a/spec/lib/gitlab/kubernetes/helm/v2/base_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/base_command_spec.rb new file mode 100644 index 00000000000..3d2b36b9094 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/v2/base_command_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Kubernetes::Helm::V2::BaseCommand do + subject(:base_command) do + test_class.new(rbac) + end + + let(:application) { create(:clusters_applications_helm) } + let(:rbac) { false } + + let(:test_class) do + Class.new(described_class) do + def initialize(rbac) + super( + name: 'test-class-name', + rbac: rbac, + files: { some: 'value' } + ) + end + end + end + + describe 'HELM_VERSION' do + subject { described_class::HELM_VERSION } + + it { is_expected.to match /^2\.\d+\.\d+$/ } + end + + describe '#env' do + subject { base_command.env } + + it { is_expected.to include(TILLER_NAMESPACE: 'gitlab-managed-apps') } + end + + it_behaves_like 'helm command generator' do + let(:commands) { '' } + end + + describe '#pod_name' do + subject { base_command.pod_name } + + it { is_expected.to eq('install-test-class-name') } + end + + it_behaves_like 'helm command' do + let(:command) { base_command } + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/certificate_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/certificate_spec.rb index b446c5e1149..a3f0fd9eb9b 100644 --- a/spec/lib/gitlab/kubernetes/helm/certificate_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v2/certificate_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::Certificate do +RSpec.describe Gitlab::Kubernetes::Helm::V2::Certificate do describe '.generate_root' do subject { described_class.generate_root } diff --git a/spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/delete_command_spec.rb index ff2c2d76f22..4a3a41dba4a 100644 --- a/spec/lib/gitlab/kubernetes/helm/delete_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v2/delete_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::DeleteCommand do +RSpec.describe Gitlab::Kubernetes::Helm::V2::DeleteCommand do subject(:delete_command) { described_class.new(name: app_name, rbac: rbac, files: files) } let(:app_name) { 'app-name' } diff --git a/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/init_command_spec.rb index d538ed12a07..8ae78ada15c 100644 --- a/spec/lib/gitlab/kubernetes/helm/init_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v2/init_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::InitCommand do +RSpec.describe Gitlab::Kubernetes::Helm::V2::InitCommand do subject(:init_command) { described_class.new(name: application.name, files: files, rbac: rbac) } let(:application) { create(:clusters_applications_helm) } diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/install_command_spec.rb index 6ed7323c96f..250d1a82e7a 100644 --- a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v2/install_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::InstallCommand do +RSpec.describe Gitlab::Kubernetes::Helm::V2::InstallCommand do subject(:install_command) do described_class.new( name: 'app-name', @@ -147,37 +147,6 @@ RSpec.describe Gitlab::Kubernetes::Helm::InstallCommand do end end - context 'when there is no ca.pem file' do - let(:files) { { 'file.txt': 'some content' } } - - it_behaves_like 'helm command generator' do - let(:commands) do - <<~EOS - export HELM_HOST="localhost:44134" - tiller -listen ${HELM_HOST} -alsologtostderr & - helm init --client-only - helm repo add app-name https://repository.example.com - helm repo update - #{helm_install_command} - EOS - end - - let(:helm_install_command) do - <<~EOS.squish - helm upgrade app-name chart-name - --install - --atomic - --cleanup-on-fail - --reset-values - --version 1.2.3 - --set rbac.create\\=false,rbac.enabled\\=false - --namespace gitlab-managed-apps - -f /data/helm/app-name/config/values.yaml - EOS - end - end - end - context 'when there is no version' do let(:version) { nil } diff --git a/spec/lib/gitlab/kubernetes/helm/patch_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/patch_command_spec.rb index 487a38f286d..98eb77d397c 100644 --- a/spec/lib/gitlab/kubernetes/helm/patch_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v2/patch_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::PatchCommand do +RSpec.describe Gitlab::Kubernetes::Helm::V2::PatchCommand do let(:files) { { 'ca.pem': 'some file content' } } let(:repository) { 'https://repository.example.com' } let(:rbac) { false } @@ -69,33 +69,6 @@ RSpec.describe Gitlab::Kubernetes::Helm::PatchCommand do end end - context 'when there is no ca.pem file' do - let(:files) { { 'file.txt': 'some content' } } - - it_behaves_like 'helm command generator' do - let(:commands) do - <<~EOS - export HELM_HOST="localhost:44134" - tiller -listen ${HELM_HOST} -alsologtostderr & - helm init --client-only - helm repo add app-name https://repository.example.com - helm repo update - #{helm_upgrade_command} - EOS - end - - let(:helm_upgrade_command) do - <<~EOS.squish - helm upgrade app-name chart-name - --reuse-values - --version 1.2.3 - --namespace gitlab-managed-apps - -f /data/helm/app-name/config/values.yaml - EOS - end - end - end - context 'when there is no version' do let(:version) { nil } diff --git a/spec/lib/gitlab/kubernetes/helm/reset_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v2/reset_command_spec.rb index 5a3ba59b8c0..9e580cea397 100644 --- a/spec/lib/gitlab/kubernetes/helm/reset_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v2/reset_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::ResetCommand do +RSpec.describe Gitlab::Kubernetes::Helm::V2::ResetCommand do subject(:reset_command) { described_class.new(name: name, rbac: rbac, files: files) } let(:rbac) { true } diff --git a/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v3/base_command_spec.rb index a7abd6ab1bf..ad5ff13b4c9 100644 --- a/spec/lib/gitlab/kubernetes/helm/base_command_spec.rb +++ b/spec/lib/gitlab/kubernetes/helm/v3/base_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Kubernetes::Helm::BaseCommand do +RSpec.describe Gitlab::Kubernetes::Helm::V3::BaseCommand do subject(:base_command) do test_class.new(rbac) end @@ -11,7 +11,7 @@ RSpec.describe Gitlab::Kubernetes::Helm::BaseCommand do let(:rbac) { false } let(:test_class) do - Class.new(Gitlab::Kubernetes::Helm::BaseCommand) do + Class.new(described_class) do def initialize(rbac) super( name: 'test-class-name', @@ -22,6 +22,12 @@ RSpec.describe Gitlab::Kubernetes::Helm::BaseCommand do end end + describe 'HELM_VERSION' do + subject { described_class::HELM_VERSION } + + it { is_expected.to match /^3\.\d+\.\d+$/ } + end + it_behaves_like 'helm command generator' do let(:commands) { '' } end diff --git a/spec/lib/gitlab/kubernetes/helm/v3/delete_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v3/delete_command_spec.rb new file mode 100644 index 00000000000..63e7a8d2f25 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/v3/delete_command_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Kubernetes::Helm::V3::DeleteCommand do + subject(:delete_command) { described_class.new(name: app_name, rbac: rbac, files: files) } + + let(:app_name) { 'app-name' } + let(:rbac) { true } + let(:files) { {} } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm uninstall app-name --namespace gitlab-managed-apps + EOS + end + end + + describe '#pod_name' do + subject { delete_command.pod_name } + + it { is_expected.to eq('uninstall-app-name') } + end + + it_behaves_like 'helm command' do + let(:command) { delete_command } + end + + describe '#delete_command' do + it 'deletes the release' do + expect(subject.delete_command).to eq('helm uninstall app-name --namespace gitlab-managed-apps') + end + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/v3/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v3/install_command_spec.rb new file mode 100644 index 00000000000..2bf1f713b3f --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/v3/install_command_spec.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Kubernetes::Helm::V3::InstallCommand do + subject(:install_command) do + described_class.new( + name: 'app-name', + chart: 'chart-name', + rbac: rbac, + files: files, + version: version, + repository: repository, + preinstall: preinstall, + postinstall: postinstall + ) + end + + let(:files) { { 'ca.pem': 'some file content' } } + let(:repository) { 'https://repository.example.com' } + let(:rbac) { false } + let(:version) { '1.2.3' } + let(:preinstall) { nil } + let(:postinstall) { nil } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + #{helm_install_comand} + EOS + end + + let(:helm_install_comand) do + <<~EOS.squish + helm upgrade app-name chart-name + --install + --atomic + --cleanup-on-fail + --reset-values + --version 1.2.3 + --set rbac.create\\=false,rbac.enabled\\=false + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + + context 'when rbac is true' do + let(:rbac) { true } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + #{helm_install_command} + EOS + end + + let(:helm_install_command) do + <<~EOS.squish + helm upgrade app-name chart-name + --install + --atomic + --cleanup-on-fail + --reset-values + --version 1.2.3 + --set rbac.create\\=true,rbac.enabled\\=true + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + end + + context 'when there is a pre-install script' do + let(:preinstall) { ['/bin/date', '/bin/true'] } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + /bin/date + /bin/true + #{helm_install_command} + EOS + end + + let(:helm_install_command) do + <<~EOS.squish + helm upgrade app-name chart-name + --install + --atomic + --cleanup-on-fail + --reset-values + --version 1.2.3 + --set rbac.create\\=false,rbac.enabled\\=false + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + end + + context 'when there is a post-install script' do + let(:postinstall) { ['/bin/date', "/bin/false\n"] } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + #{helm_install_command} + /bin/date + /bin/false + EOS + end + + let(:helm_install_command) do + <<~EOS.squish + helm upgrade app-name chart-name + --install + --atomic + --cleanup-on-fail + --reset-values + --version 1.2.3 + --set rbac.create\\=false,rbac.enabled\\=false + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + end + + context 'when there is no version' do + let(:version) { nil } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + #{helm_install_command} + EOS + end + + let(:helm_install_command) do + <<~EOS.squish + helm upgrade app-name chart-name + --install + --atomic + --cleanup-on-fail + --reset-values + --set rbac.create\\=false,rbac.enabled\\=false + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + end + + it_behaves_like 'helm command' do + let(:command) { install_command } + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/v3/patch_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/v3/patch_command_spec.rb new file mode 100644 index 00000000000..2f22e0f2e77 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/v3/patch_command_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Kubernetes::Helm::V3::PatchCommand do + let(:files) { { 'ca.pem': 'some file content' } } + let(:repository) { 'https://repository.example.com' } + let(:rbac) { false } + let(:version) { '1.2.3' } + + subject(:patch_command) do + described_class.new( + name: 'app-name', + chart: 'chart-name', + rbac: rbac, + files: files, + version: version, + repository: repository + ) + end + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + #{helm_upgrade_comand} + EOS + end + + let(:helm_upgrade_comand) do + <<~EOS.squish + helm upgrade app-name chart-name + --reuse-values + --version 1.2.3 + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + + context 'when rbac is true' do + let(:rbac) { true } + + it_behaves_like 'helm command generator' do + let(:commands) do + <<~EOS + helm repo add app-name https://repository.example.com + helm repo update + #{helm_upgrade_command} + EOS + end + + let(:helm_upgrade_command) do + <<~EOS.squish + helm upgrade app-name chart-name + --reuse-values + --version 1.2.3 + --namespace gitlab-managed-apps + -f /data/helm/app-name/config/values.yaml + EOS + end + end + end + + context 'when there is no version' do + let(:version) { nil } + + it { expect { patch_command }.to raise_error(ArgumentError, 'version is required') } + end + + describe '#pod_name' do + subject { patch_command.pod_name } + + it { is_expected.to eq 'install-app-name' } + end + + it_behaves_like 'helm command' do + let(:command) { patch_command } + end +end diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb index 7ca7f533a27..3044260a000 100644 --- a/spec/models/clusters/applications/cert_manager_spec.rb +++ b/spec/models/clusters/applications/cert_manager_spec.rb @@ -40,7 +40,7 @@ RSpec.describe Clusters::Applications::CertManager do subject { cert_manager.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with cert_manager arguments' do expect(subject.name).to eq('certmanager') @@ -90,7 +90,7 @@ RSpec.describe Clusters::Applications::CertManager do describe '#uninstall_command' do subject { cert_manager.uninstall_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::DeleteCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) } it 'is initialized with cert_manager arguments' do expect(subject.name).to eq('certmanager') diff --git a/spec/models/clusters/applications/crossplane_spec.rb b/spec/models/clusters/applications/crossplane_spec.rb index a41c5f6586b..7082576028b 100644 --- a/spec/models/clusters/applications/crossplane_spec.rb +++ b/spec/models/clusters/applications/crossplane_spec.rb @@ -25,7 +25,7 @@ RSpec.describe Clusters::Applications::Crossplane do subject { crossplane.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with crossplane arguments' do expect(subject.name).to eq('crossplane') diff --git a/spec/models/clusters/applications/elastic_stack_spec.rb b/spec/models/clusters/applications/elastic_stack_spec.rb index 62123ffa542..74cacd486b0 100644 --- a/spec/models/clusters/applications/elastic_stack_spec.rb +++ b/spec/models/clusters/applications/elastic_stack_spec.rb @@ -15,7 +15,7 @@ RSpec.describe Clusters::Applications::ElasticStack do subject { elastic_stack.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with elastic stack arguments' do expect(subject.name).to eq('elastic-stack') @@ -57,7 +57,7 @@ RSpec.describe Clusters::Applications::ElasticStack do it 'includes a preinstall script' do expect(subject.preinstall).not_to be_empty - expect(subject.preinstall.first).to include("delete") + expect(subject.preinstall.first).to include("helm uninstall") end end @@ -69,7 +69,7 @@ RSpec.describe Clusters::Applications::ElasticStack do it 'includes a preinstall script' do expect(subject.preinstall).not_to be_empty - expect(subject.preinstall.first).to include("delete") + expect(subject.preinstall.first).to include("helm uninstall") end end @@ -123,7 +123,7 @@ RSpec.describe Clusters::Applications::ElasticStack do subject { elastic_stack.uninstall_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::DeleteCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) } it 'is initialized with elastic stack arguments' do expect(subject.name).to eq('elastic-stack') diff --git a/spec/models/clusters/applications/fluentd_spec.rb b/spec/models/clusters/applications/fluentd_spec.rb index 3bda3e99ec1..ccdf6b0e40d 100644 --- a/spec/models/clusters/applications/fluentd_spec.rb +++ b/spec/models/clusters/applications/fluentd_spec.rb @@ -21,7 +21,7 @@ RSpec.describe Clusters::Applications::Fluentd do describe '#install_command' do subject { fluentd.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with fluentd arguments' do expect(subject.name).to eq('fluentd') diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb index 6d2ecaa6d47..ad1ebd4966a 100644 --- a/spec/models/clusters/applications/helm_spec.rb +++ b/spec/models/clusters/applications/helm_spec.rb @@ -56,7 +56,7 @@ RSpec.describe Clusters::Applications::Helm do subject { application.issue_client_cert } it 'returns a new cert' do - is_expected.to be_kind_of(Gitlab::Kubernetes::Helm::Certificate) + is_expected.to be_kind_of(Gitlab::Kubernetes::Helm::V2::Certificate) expect(subject.cert_string).not_to eq(application.ca_cert) expect(subject.key_string).not_to eq(application.ca_key) end @@ -67,7 +67,7 @@ RSpec.describe Clusters::Applications::Helm do subject { helm.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InitCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V2::InitCommand) } it 'is initialized with 1 arguments' do expect(subject.name).to eq('helm') @@ -104,7 +104,7 @@ RSpec.describe Clusters::Applications::Helm do subject { helm.uninstall_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::ResetCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V2::ResetCommand) } it 'has name' do expect(subject.name).to eq('helm') diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index 196d57aff7b..1bc1a4343aa 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -131,7 +131,7 @@ RSpec.describe Clusters::Applications::Ingress do describe '#install_command' do subject { ingress.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with ingress arguments' do expect(subject.name).to eq('ingress') diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb index 3cf24f1a9ef..e7de2d24334 100644 --- a/spec/models/clusters/applications/jupyter_spec.rb +++ b/spec/models/clusters/applications/jupyter_spec.rb @@ -52,7 +52,7 @@ RSpec.describe Clusters::Applications::Jupyter do subject { jupyter.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with 4 arguments' do expect(subject.name).to eq('jupyter') diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb index b14161ce8e6..41b4ec86233 100644 --- a/spec/models/clusters/applications/knative_spec.rb +++ b/spec/models/clusters/applications/knative_spec.rb @@ -119,7 +119,7 @@ RSpec.describe Clusters::Applications::Knative do shared_examples 'a command' do it 'is an instance of Helm::InstallCommand' do - expect(subject).to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) + expect(subject).to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) end it 'is initialized with knative arguments' do @@ -171,7 +171,7 @@ RSpec.describe Clusters::Applications::Knative do describe '#uninstall_command' do subject { knative.uninstall_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::DeleteCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) } it "removes knative deployed services before uninstallation" do 2.times do |i| diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index b450900bee6..032de6aa7c2 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -148,7 +148,7 @@ RSpec.describe Clusters::Applications::Prometheus do subject { prometheus.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with 3 arguments' do expect(subject.name).to eq('prometheus') @@ -195,7 +195,7 @@ RSpec.describe Clusters::Applications::Prometheus do subject { prometheus.uninstall_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::DeleteCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) } it 'has the application name' do expect(subject.name).to eq('prometheus') @@ -236,7 +236,7 @@ RSpec.describe Clusters::Applications::Prometheus do let(:prometheus) { build(:clusters_applications_prometheus) } let(:values) { prometheus.values } - it { is_expected.to be_an_instance_of(::Gitlab::Kubernetes::Helm::PatchCommand) } + it { is_expected.to be_an_instance_of(::Gitlab::Kubernetes::Helm::V3::PatchCommand) } it 'is initialized with 3 arguments' do expect(patch_command.name).to eq('prometheus') diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index ef916c73e0b..43e2eab3b9d 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -27,7 +27,7 @@ RSpec.describe Clusters::Applications::Runner do subject { gitlab_runner.install_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::InstallCommand) } it 'is initialized with 4 arguments' do expect(subject.name).to eq('runner') diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index dd9b96f39ad..ed74a841044 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -540,6 +540,27 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do end end end + + describe 'helm_major_version can only be 2 or 3' do + using RSpec::Parameterized::TableSyntax + + where(:helm_major_version, :expect_valid) do + 2 | true + 3 | true + 4 | false + -1 | false + end + + with_them do + let(:cluster) { build(:cluster, helm_major_version: helm_major_version) } + + it { is_expected.to eq(expect_valid) } + end + end + end + + it 'has default helm_major_version 3' do + expect(create(:cluster).helm_major_version).to eq(3) end describe '.ancestor_clusters_for_clusterable' do diff --git a/spec/requests/api/graphql/project/release_spec.rb b/spec/requests/api/graphql/project/release_spec.rb index ade7cc177be..57b620dbdf7 100644 --- a/spec/requests/api/graphql/project/release_spec.rb +++ b/spec/requests/api/graphql/project/release_spec.rb @@ -189,8 +189,6 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do closedMergeRequestsUrl openedIssuesUrl closedIssuesUrl - mergeRequestsUrl - issuesUrl }) end @@ -203,9 +201,7 @@ RSpec.describe 'Query.project(fullPath).release(tagName)' do 'mergedMergeRequestsUrl' => project_merge_requests_url(project, merged_url_params), 'closedMergeRequestsUrl' => project_merge_requests_url(project, closed_url_params), 'openedIssuesUrl' => project_issues_url(project, opened_url_params), - 'closedIssuesUrl' => project_issues_url(project, closed_url_params), - 'mergeRequestsUrl' => project_merge_requests_url(project, opened_url_params), - 'issuesUrl' => project_issues_url(project, opened_url_params) + 'closedIssuesUrl' => project_issues_url(project, closed_url_params) ) end end diff --git a/spec/requests/api/graphql/project/releases_spec.rb b/spec/requests/api/graphql/project/releases_spec.rb index 9288dab3f2e..6e364c7d7b5 100644 --- a/spec/requests/api/graphql/project/releases_spec.rb +++ b/spec/requests/api/graphql/project/releases_spec.rb @@ -47,8 +47,6 @@ RSpec.describe 'Query.project(fullPath).releases()' do closedMergeRequestsUrl openedIssuesUrl closedIssuesUrl - mergeRequestsUrl - issuesUrl } } } @@ -115,9 +113,7 @@ RSpec.describe 'Query.project(fullPath).releases()' do 'mergedMergeRequestsUrl' => project_merge_requests_url(project, merged_url_params), 'closedMergeRequestsUrl' => project_merge_requests_url(project, closed_url_params), 'openedIssuesUrl' => project_issues_url(project, opened_url_params), - 'closedIssuesUrl' => project_issues_url(project, closed_url_params), - 'mergeRequestsUrl' => project_merge_requests_url(project, opened_url_params), - 'issuesUrl' => project_issues_url(project, opened_url_params) + 'closedIssuesUrl' => project_issues_url(project, closed_url_params) } ) end diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb index e78d05835f2..f8e4cfbb9e5 100644 --- a/spec/requests/api/releases_spec.rb +++ b/spec/requests/api/releases_spec.rb @@ -110,22 +110,6 @@ RSpec.describe API::Releases do expect(json_response.second['commit_path']).to eq("/#{release_1.project.full_path}/-/commit/#{release_1.commit.id}") expect(json_response.second['tag_path']).to eq("/#{release_1.project.full_path}/-/tags/#{release_1.tag}") end - - it 'returns the merge requests and issues links, with correct query' do - get api("/projects/#{project.id}/releases", maintainer) - - links = json_response.first['_links'] - release = json_response.first['tag_name'] - expected_query = "release_tag=#{release}&scope=all&state=opened" - path_base = "/#{project.namespace.path}/#{project.path}" - mr_uri = URI.parse(links['merge_requests_url']) - issue_uri = URI.parse(links['issues_url']) - - expect(mr_uri.path).to eq("#{path_base}/-/merge_requests") - expect(issue_uri.path).to eq("#{path_base}/-/issues") - expect(mr_uri.query).to eq(expected_query) - expect(issue_uri.query).to eq(expected_query) - end end it 'returns an upcoming_release status for a future release' do diff --git a/spec/services/clusters/applications/uninstall_service_spec.rb b/spec/services/clusters/applications/uninstall_service_spec.rb index 50d7e82c47e..bfe38ba670d 100644 --- a/spec/services/clusters/applications/uninstall_service_spec.rb +++ b/spec/services/clusters/applications/uninstall_service_spec.rb @@ -14,7 +14,7 @@ RSpec.describe Clusters::Applications::UninstallService, '#execute' do context 'when there are no errors' do before do - expect(helm_client).to receive(:uninstall).with(kind_of(Gitlab::Kubernetes::Helm::DeleteCommand)) + expect(helm_client).to receive(:uninstall).with(kind_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand)) allow(worker_class).to receive(:perform_in).and_return(nil) end @@ -36,7 +36,7 @@ RSpec.describe Clusters::Applications::UninstallService, '#execute' do let(:error) { Kubeclient::HttpError.new(500, 'system failure', nil) } before do - expect(helm_client).to receive(:uninstall).with(kind_of(Gitlab::Kubernetes::Helm::DeleteCommand)).and_raise(error) + expect(helm_client).to receive(:uninstall).with(kind_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand)).and_raise(error) end include_examples 'logs kubernetes errors' do @@ -58,7 +58,7 @@ RSpec.describe Clusters::Applications::UninstallService, '#execute' do let(:error) { StandardError.new('something bad happened') } before do - expect(helm_client).to receive(:uninstall).with(kind_of(Gitlab::Kubernetes::Helm::DeleteCommand)).and_raise(error) + expect(helm_client).to receive(:uninstall).with(kind_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand)).and_raise(error) end include_examples 'logs kubernetes errors' do diff --git a/spec/support/shared_examples/helm_commands_shared_examples.rb b/spec/support/shared_examples/helm_commands_shared_examples.rb index 0a94c6648cc..64f176c5ae9 100644 --- a/spec/support/shared_examples/helm_commands_shared_examples.rb +++ b/spec/support/shared_examples/helm_commands_shared_examples.rb @@ -15,6 +15,18 @@ RSpec.shared_examples 'helm command generator' do end RSpec.shared_examples 'helm command' do + describe 'HELM_VERSION' do + subject { command.class::HELM_VERSION } + + it { is_expected.to match(/\d+\.\d+\.\d+/) } + end + + describe '#env' do + subject { command.env } + + it { is_expected.to be_a Hash } + end + describe '#rbac?' do subject { command.rbac? } diff --git a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb index 85a7c90ee42..51071ae47c3 100644 --- a/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb +++ b/spec/support/shared_examples/models/cluster_application_core_shared_examples.rb @@ -25,4 +25,21 @@ RSpec.shared_examples 'cluster application core specs' do |application_name| describe '.association_name' do it { expect(described_class.association_name).to eq(:"application_#{subject.name}") } end + + describe '#helm_command_module' do + using RSpec::Parameterized::TableSyntax + + where(:helm_major_version, :expected_helm_command_module) do + 2 | Gitlab::Kubernetes::Helm::V2 + 3 | Gitlab::Kubernetes::Helm::V3 + end + + with_them do + subject { described_class.new(cluster: cluster).helm_command_module } + + let(:cluster) { build(:cluster, helm_major_version: helm_major_version)} + + it { is_expected.to eq(expected_helm_command_module) } + end + end end diff --git a/spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb b/spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb index ac8022a4726..187a44ec3cd 100644 --- a/spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb +++ b/spec/support/shared_examples/models/cluster_application_helm_cert_shared_examples.rb @@ -6,7 +6,7 @@ RSpec.shared_examples 'cluster application helm specs' do |application_name| describe '#uninstall_command' do subject { application.uninstall_command } - it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::DeleteCommand) } + it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::V3::DeleteCommand) } it 'has files' do expect(subject.files).to eq(application.files) |