diff --git a/app/controllers/katello/api/v2/content_view_components_controller.rb b/app/controllers/katello/api/v2/content_view_components_controller.rb
index 4fc835c4ea8..d77d9bce919 100644
--- a/app/controllers/katello/api/v2/content_view_components_controller.rb
+++ b/app/controllers/katello/api/v2/content_view_components_controller.rb
@@ -47,7 +47,7 @@ def show_all
CAST (#{kcc}.composite_content_view_id as BOOLEAN) ASC, #{kc}.name
SQL
query = Katello::ContentView.readable.in_organization(@organization)
- query = query&.non_composite&.non_default&.generated_for_none
+ query = query&.non_composite&.non_default&.non_rolling&.generated_for_none
component_cv_ids = Katello::ContentViewComponent.where(composite_content_view_id: @view.id).select(:content_view_id)
query = case params[:status]
when "Not added"
@@ -145,23 +145,23 @@ def update
def get_total(status)
case status
when 'All'
- return Katello::ContentView.non_default.non_composite.in_organization(@organization).count
+ return Katello::ContentView.non_default.non_composite.non_rolling.in_organization(@organization).count
when 'Added'
return Katello::ContentViewComponent.where(composite_content_view_id: @view.id).count
when 'Not added'
- return Katello::ContentView.non_default.non_composite.in_organization(@organization).count - Katello::ContentViewComponent.where(composite_content_view_id: @view.id).count
+ return Katello::ContentView.non_default.non_composite.non_rolling.in_organization(@organization).count - Katello::ContentViewComponent.where(composite_content_view_id: @view.id).count
else
- return Katello::ContentView.non_default.non_composite.in_organization(@organization).count
+ return Katello::ContentView.non_default.non_composite.non_rolling.in_organization(@organization).count
end
end
def find_composite_content_view
- @view = ContentView.composite.non_default.readable.find_by(id: params[:composite_content_view_id])
+ @view = ContentView.composite.non_default.non_rolling.readable.find_by(id: params[:composite_content_view_id])
throw_resource_not_found(name: 'composite content view', id: params[:composite_content_view_id]) if @view.nil?
end
def find_composite_content_view_for_edit
- @view = ContentView.composite.non_default.editable.find_by(id: params[:composite_content_view_id])
+ @view = ContentView.composite.non_default.non_rolling.editable.find_by(id: params[:composite_content_view_id])
throw_resource_not_found(name: 'composite content view', id: params[:composite_content_view_id]) if @view.nil?
end
diff --git a/app/controllers/katello/api/v2/content_view_filters_controller.rb b/app/controllers/katello/api/v2/content_view_filters_controller.rb
index 2d9ac705783..8acda4ba093 100644
--- a/app/controllers/katello/api/v2/content_view_filters_controller.rb
+++ b/app/controllers/katello/api/v2/content_view_filters_controller.rb
@@ -43,6 +43,9 @@ def index_relation
param :repository_ids, Array, :desc => N_("list of repository ids")
param :description, String, :desc => N_("description of the filter")
def create
+ if @view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to create a filter for a rolling content view.")
+ end
params[:type] = "erratum" if (params[:type] == "erratum_date" || params[:type] == "erratum_id")
filter = ContentViewFilter.create_for(params[:type], filter_params.merge(:content_view => @view))
respond :resource => filter
diff --git a/app/controllers/katello/api/v2/content_view_versions_controller.rb b/app/controllers/katello/api/v2/content_view_versions_controller.rb
index f7917c47528..07a1ba94bce 100644
--- a/app/controllers/katello/api/v2/content_view_versions_controller.rb
+++ b/app/controllers/katello/api/v2/content_view_versions_controller.rb
@@ -60,6 +60,9 @@ def show
param :environment_ids, Array, :desc => N_("Identifiers for Lifecycle Environment")
param :description, String, :desc => N_("The description for the content view version promotion")
def promote
+ if @view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to promote a rolling content view.")
+ end
is_force = ::Foreman::Cast.to_bool(params[:force])
task = async_task(::Actions::Katello::ContentView::Promote,
@content_view_version, @environments, is_force, params[:description])
@@ -97,6 +100,9 @@ def republish_repositories
api :DELETE, "/content_view_versions/:id", N_("Remove content view version")
param :id, :number, :desc => N_("Content view version identifier"), :required => true
def destroy
+ if @view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to destroy a version of a rolling content view.")
+ end
task = async_task(::Actions::Katello::ContentViewVersion::Destroy, @content_view_version)
respond_for_async :resource => task
end
diff --git a/app/controllers/katello/api/v2/content_views_controller.rb b/app/controllers/katello/api/v2/content_views_controller.rb
index a182c1eaa48..8f215cc132e 100644
--- a/app/controllers/katello/api/v2/content_views_controller.rb
+++ b/app/controllers/katello/api/v2/content_views_controller.rb
@@ -13,6 +13,7 @@ class Api::V2::ContentViewsController < Api::V2::ApiController
wrap_parameters :include => (ContentView.attribute_names + %w(repository_ids component_ids))
+ around_action :add_to_environment, :only => [:create]
resource_description do
api_version "v2"
end
@@ -84,6 +85,7 @@ def index_relation
param :name, String, :desc => N_("Name of the content view"), :required => true
param :label, String, :desc => N_("Content view label")
param :composite, :bool, :desc => N_("Composite content view")
+ param :rolling, :bool, :desc => N_("Rolling content view")
param_group :content_view
def create
@content_view = ContentView.create!(view_params) do |view|
@@ -192,6 +194,9 @@ def remove
param :key_content_view_id, :number, :desc => N_("content view to reassign orphaned activation keys to")
param :key_environment_id, :number, :desc => N_("environment to reassign orphaned activation keys to")
def bulk_delete_versions
+ if @content_view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to bulk remove versions from a rolling content view.")
+ end
params[:bulk_content_view_version_ids] ||= {}
versions = find_bulk_items(bulk_params: params[:bulk_content_view_version_ids],
@@ -237,6 +242,9 @@ def destroy
param :name, String, :required => true, :desc => N_("New content view name")
def copy
@content_view = Katello::ContentView.readable.find_by(:id => params[:id])
+ if @content_view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to copy a rolling content view.")
+ end
throw_resource_not_found(name: 'content_view', id: params[:id]) if @content_view.blank?
ensure_non_default
new_content_view = @content_view.copy(params[:content_view][:name])
@@ -246,6 +254,9 @@ def copy
private
def validate_publish_params!
+ if @content_view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to publish a rolling content view.")
+ end
if params[:repos_units].present? && @content_view.composite?
fail HttpErrors::BadRequest, _("Directly setting package lists on composite content views is not allowed. Please " \
"update the components, then re-publish the composite.")
@@ -284,11 +295,14 @@ def ensure_non_generated
def view_params
attrs = [:name, :description, :auto_publish, :solve_dependencies, :import_only,
:default, :created_at, :updated_at, :next_version, {:component_ids => []}]
- attrs.push(:label, :composite) if action_name == "create"
+ attrs.push(:label, :composite, :rolling) if action_name == "create"
if (!@content_view || !@content_view.composite?)
attrs.push({:repository_ids => []}, :repository_ids)
end
- params.require(:content_view).permit(*attrs).to_h
+ result = params.require(:content_view).permit(*attrs).to_h
+ # sanitize repository_ids to be a list of integers
+ result[:repository_ids] = result[:repository_ids].map(&:to_i) if result[:repository_ids].present?
+ result
end
def find_environment
@@ -307,5 +321,11 @@ def add_use_latest_records(module_records, selected_latest_versions)
end
module_records
end
+
+ def add_to_environment
+ yield
+ return unless params[:rolling]
+ async_task(::Actions::Katello::ContentView::AddToEnvironment, @content_view.create_new_version, @content_view.organization.library)
+ end
end
end
diff --git a/app/controllers/katello/api/v2/exports_controller.rb b/app/controllers/katello/api/v2/exports_controller.rb
index 55f6b50c776..3ff84dc3515 100644
--- a/app/controllers/katello/api/v2/exports_controller.rb
+++ b/app/controllers/katello/api/v2/exports_controller.rb
@@ -108,6 +108,9 @@ def find_exportable_content_view_version
@version = ContentViewVersion.exportable.find_by_id(params[:id])
throw_resource_not_found(name: 'content view version', id: params[:id]) if @version.blank?
@view = @version.content_view
+ if @view.rolling?
+ fail HttpErrors::BadRequest, _("It's not possible to export a rolling content view.")
+ end
end
def find_history
diff --git a/app/lib/actions/helpers/rolling_cv_repos.rb b/app/lib/actions/helpers/rolling_cv_repos.rb
new file mode 100644
index 00000000000..8cb06c0ffbb
--- /dev/null
+++ b/app/lib/actions/helpers/rolling_cv_repos.rb
@@ -0,0 +1,17 @@
+module Actions
+ module Helpers
+ module RollingCVRepos
+ def update_rolling_content_views(repo)
+ concurrence do
+ repos = repo.root.repositories.in_environment(repo.environment).where(
+ content_view_version: ::Katello::ContentViewVersion.where(content_view: ::Katello::ContentView.rolling)
+ )
+
+ repos.each do |rolling_repo|
+ plan_action(::Actions::Katello::ContentView::RefreshRollingRepo, rolling_repo)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb b/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb
new file mode 100644
index 00000000000..cf89308d5ce
--- /dev/null
+++ b/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb
@@ -0,0 +1,28 @@
+module Actions
+ module Katello
+ module ContentView
+ class AddRollingRepoClone < Actions::EntryAction
+ def plan(content_view, repository_ids)
+ library = content_view.organization.library
+
+ concurrence do
+ ::Katello::Repository.where(id: repository_ids).each do |repository|
+ sequence do
+ clone = content_view.get_repo_clone(library, repository).first
+ if clone.nil?
+ clone = repository.build_clone(content_view: content_view, environment: library)
+ clone.save!
+ end
+ plan_action(RefreshRollingRepo, clone)
+
+ view_env_cp_id = content_view.content_view_environment(library).cp_id
+ content_id = repository.content_id
+ plan_action(Actions::Candlepin::Environment::AddContentToEnvironment, :view_env_cp_id => view_env_cp_id, :content_id => content_id)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/lib/actions/katello/content_view/refresh_rolling_repo.rb b/app/lib/actions/katello/content_view/refresh_rolling_repo.rb
new file mode 100644
index 00000000000..a11ea6582c3
--- /dev/null
+++ b/app/lib/actions/katello/content_view/refresh_rolling_repo.rb
@@ -0,0 +1,30 @@
+module Actions
+ module Katello
+ module ContentView
+ class RefreshRollingRepo < Actions::EntryAction
+ def plan(repository)
+ action_subject repository
+ sequence do
+ plan_self(repository_id: repository.id)
+ plan_action(Pulp3::Repository::RefreshDistribution, repository, SmartProxy.pulp_primary)
+ plan_action(Repository::IndexContent, id: repository.id, source_repository_id: repository.library_instance.id)
+ end
+ end
+
+ def run
+ repository = ::Katello::Repository.find(input[:repository_id])
+ library_instance = repository.library_instance
+ # ensure IndexContent is not skipped!
+ repository.last_contents_changed = DateTime.now if repository.version_href != library_instance.version_href
+
+ repository.version_href = library_instance.version_href
+ repository.publication_href = library_instance.publication_href
+ if repository.deb_using_structured_apt?
+ repository.content_id = library_instance.content_id
+ end
+ repository.save!
+ end
+ end
+ end
+ end
+end
diff --git a/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb b/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb
new file mode 100644
index 00000000000..b823acbc4fe
--- /dev/null
+++ b/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb
@@ -0,0 +1,28 @@
+module Actions
+ module Katello
+ module ContentView
+ class RemoveRollingRepoClone < Actions::EntryAction
+ def plan(content_view, repository_ids)
+ library = content_view.organization.library
+
+ clone_repo_ids = []
+ concurrence do
+ ::Katello::Repository.where(id: repository_ids).each do |repository|
+ clone_repo = content_view.get_repo_clone(library, repository).first
+ next if clone_repo.nil?
+
+ clone_repo_ids << clone_repo.id
+ plan_action(Actions::Pulp3::Repository::DeleteDistributions, clone_repo.id, SmartProxy.pulp_primary)
+ end
+ plan_action(Candlepin::Environment::SetContent, content_view, library, content_view.content_view_environment(library))
+ end
+ plan_self(repository_ids: clone_repo_ids)
+ end
+
+ def run
+ ::Katello::Repository.where(id: input[:repository_ids]).destroy_all
+ end
+ end
+ end
+ end
+end
diff --git a/app/lib/actions/katello/content_view/update.rb b/app/lib/actions/katello/content_view/update.rb
index b54d53b6e80..47b2d624dc3 100644
--- a/app/lib/actions/katello/content_view/update.rb
+++ b/app/lib/actions/katello/content_view/update.rb
@@ -28,6 +28,14 @@ def plan(content_view, content_view_params)
end
end
+ if content_view.rolling? && content_view_params.key?(:repository_ids)
+ repo_ids_to_add = content_view_params[:repository_ids] - content_view.repository_ids
+ repo_ids_to_remove = content_view.repository_ids - content_view_params[:repository_ids]
+
+ plan_action(AddRollingRepoClone, content_view, repo_ids_to_add) if repo_ids_to_add.any?
+ plan_action(RemoveRollingRepoClone, content_view, repo_ids_to_remove) if repo_ids_to_remove.any?
+ end
+
content_view.update!(content_view_params)
end
end
diff --git a/app/lib/actions/katello/repository/import_upload.rb b/app/lib/actions/katello/repository/import_upload.rb
index cce4a7514cc..a2e8dc47e72 100644
--- a/app/lib/actions/katello/repository/import_upload.rb
+++ b/app/lib/actions/katello/repository/import_upload.rb
@@ -3,6 +3,8 @@ module Actions
module Katello
module Repository
class ImportUpload < Actions::EntryAction
+ include Helpers::RollingCVRepos
+
# rubocop:disable Metrics/MethodLength
def plan(repository, uploads, options = {})
action_subject(repository)
@@ -52,6 +54,9 @@ def plan(repository, uploads, options = {})
plan_action(Katello::Repository::MetadataGenerate, repository, force_publication: true) if generate_metadata
plan_action(Actions::Katello::Applicability::Repository::Regenerate, :repo_ids => [repository.id]) if generate_applicability
plan_self(repository_id: repository.id, sync_capsule: sync_capsule, upload_results: upload_results)
+
+ # Refresh rolling CVs that have this repository
+ update_rolling_content_views(repository)
end
end
# rubocop:enable Metrics/MethodLength
diff --git a/app/lib/actions/katello/repository/sync.rb b/app/lib/actions/katello/repository/sync.rb
index cb5203dbbd5..881b829eb3e 100644
--- a/app/lib/actions/katello/repository/sync.rb
+++ b/app/lib/actions/katello/repository/sync.rb
@@ -5,6 +5,7 @@ module Repository
class Sync < Actions::EntryAction
extend ApipieDSL::Class
include Helpers::Presenter
+ include Helpers::RollingCVRepos
include ::Actions::ObservableAction
middleware.use Actions::Middleware::ExecuteIfContentsChanged
@@ -56,6 +57,7 @@ def plan(repo, options = {})
end
plan_self(:id => repo.id, :sync_result => output, :skip_metadata_check => skip_metadata_check, :validate_contents => validate_contents,
:contents_changed => output[:contents_changed])
+ update_rolling_content_views(repo)
plan_action(Katello::Repository::SyncHook, :id => repo.id)
end
end
diff --git a/app/lib/actions/katello/repository/upload_files.rb b/app/lib/actions/katello/repository/upload_files.rb
index 839e206db8d..345da36d361 100644
--- a/app/lib/actions/katello/repository/upload_files.rb
+++ b/app/lib/actions/katello/repository/upload_files.rb
@@ -6,6 +6,8 @@ module Actions
module Katello
module Repository
class UploadFiles < Actions::EntryAction
+ include Helpers::RollingCVRepos
+
def plan(repository, files, content_type = nil, options = {})
action_subject(repository)
repository.check_ready_to_act!
@@ -38,6 +40,9 @@ def plan(repository, files, content_type = nil, options = {})
plan_action(FinishUpload, repository, content_type: content_type, upload_actions: upload_actions)
plan_self(tmp_files: tmp_files)
plan_action(Actions::Katello::Applicability::Repository::Regenerate, :repo_ids => [repository.id]) if generate_applicability
+
+ # Refresh rolling CVs that have this repository
+ update_rolling_content_views(repository)
end
ensure
# Delete tmp files when some exception occurred. Would be
@@ -46,7 +51,8 @@ def plan(repository, files, content_type = nil, options = {})
end
def run
- ForemanTasks.async_task(Repository::CapsuleSync, ::Katello::Repository.find(input[:repository][:id])) if Setting[:foreman_proxy_content_auto_sync]
+ repository = ::Katello::Repository.find(input[:repository][:id])
+ ForemanTasks.async_task(Repository::CapsuleSync, repository) if Setting[:foreman_proxy_content_auto_sync]
rescue ::Katello::Errors::CapsuleCannotBeReached # skip any capsules that cannot be connected to
end
diff --git a/app/models/katello/content_view.rb b/app/models/katello/content_view.rb
index e13cb2f9735..a4354f8aa2a 100644
--- a/app/models/katello/content_view.rb
+++ b/app/models/katello/content_view.rb
@@ -71,6 +71,16 @@ class ContentView < Katello::Model
validates :composite,
inclusion: { in: [false], message: "Composite Content Views can not solve dependencies" },
if: :solve_dependencies
+ validates :rolling, :inclusion => [true, false]
+ validates :rolling,
+ inclusion: { in: [false], message: "Rolling content views can not solve dependencies" },
+ if: :solve_dependencies
+ validates :rolling,
+ inclusion: { in: [false], message: "Rolling content views can not be composite" },
+ if: :composite
+ validates :rolling,
+ inclusion: { in: [false], message: "Rolling content views can not be import only" },
+ if: :import_only
validates :import_only, :inclusion => [true, false]
validates :import_only,
inclusion: { in: [false], message: "Import-only Content Views can not be Composite" },
@@ -93,6 +103,8 @@ class ContentView < Katello::Model
scope :non_default, -> { where(:default => false) }
scope :composite, -> { where(:composite => true) }
scope :non_composite, -> { where(:composite => [nil, false]) }
+ scope :rolling, -> { where(:rolling => true) }
+ scope :non_rolling, -> { where(:rolling => [nil, false]) }
scope :generated, -> { where.not(:generated_for => :none) }
scope :generated_for_repository, -> {
where(:generated_for => [:repository_export,
@@ -113,6 +125,7 @@ class ContentView < Katello::Model
scoped_search :on => :organization_id, :complete_value => true, :only_explicit => true, :validator => ScopedSearch::Validators::INTEGER
scoped_search :on => :label, :complete_value => true
scoped_search :on => :composite, :complete_value => { :true => true, :false => false }
+ scoped_search :on => :rolling, :complete_value => { :true => true, :false => false }
scoped_search :on => :generated_for, :complete_value => true
scoped_search :on => :default # just for ordering
scoped_search :on => :name, :complete_value => true,
@@ -802,7 +815,7 @@ def cv_repo_indexed_after_last_published?
end
def unpublishable?
- default? || import_only? || generated?
+ default? || import_only? || generated? || rolling?
end
def needs_publish?
diff --git a/app/models/katello/content_view_component.rb b/app/models/katello/content_view_component.rb
index 61379aed36c..d89c25d010b 100644
--- a/app/models/katello/content_view_component.rb
+++ b/app/models/katello/content_view_component.rb
@@ -53,6 +53,10 @@ def ensure_valid_content_view
errors.add(:base, _("Cannot add default content view to composite content view"))
end
+ if view.rolling?
+ errors.add(:base, _("Cannot add rolling content view to composite content view"))
+ end
+
if attached_content_view_ids.include?(view.id)
errors.add(:base, _("Another component already includes content view with ID %s" % view.id))
end
diff --git a/app/models/katello/content_view_version.rb b/app/models/katello/content_view_version.rb
index 530912a23bc..85daf75b1b4 100644
--- a/app/models/katello/content_view_version.rb
+++ b/app/models/katello/content_view_version.rb
@@ -45,6 +45,7 @@ class ContentViewVersion < Katello::Model
:class_name => "Katello::ContentViewVersion", :inverse_of => :components
has_many :published_in_composite_content_views, through: :composites, source: :content_view
delegate :default, :default?, to: :content_view
+ delegate :rolling, :rolling?, to: :content_view
validates_lengths_from_database
@@ -383,7 +384,7 @@ def content_counts_map
end
def check_ready_to_promote!(to_env)
- fail _("Default content view versions cannot be promoted") if default?
+ fail _("Default and Rolling content view versions cannot be promoted") if default? || rolling?
content_view.check_composite_action_allowed!(to_env)
content_view.check_docker_repository_names!(to_env)
content_view.check_orphaned_content_facets!(environments: [to_env])
diff --git a/app/models/katello/repository.rb b/app/models/katello/repository.rb
index 3abccdeb136..d0a1b9f3f9b 100644
--- a/app/models/katello/repository.rb
+++ b/app/models/katello/repository.rb
@@ -718,6 +718,8 @@ def environmental_instances(view)
def archived_instance
if self.environment_id.nil? || self.library_instance_id.nil?
self
+ elsif self.content_view.rolling?
+ self.library_instance
else
self.content_view_version.archived_repos.where(:root_id => self.root_id).first
end
diff --git a/app/views/katello/api/v2/capsule_content/sync_status.json.rabl b/app/views/katello/api/v2/capsule_content/sync_status.json.rabl
index 298ad550f7d..029d384c47c 100644
--- a/app/views/katello/api/v2/capsule_content/sync_status.json.rabl
+++ b/app/views/katello/api/v2/capsule_content/sync_status.json.rabl
@@ -67,6 +67,7 @@ child @lifecycle_environments => :lifecycle_environments do
:label => content_view.label,
:name => content_view.name,
:composite => content_view.composite,
+ :rolling => content_view.rolling,
:last_published => content_view.versions.empty? ? nil : content_view.versions.in_environment(env).first&.created_at,
:default => content_view.default,
:up_to_date => @capsule.repos_pending_sync(env, content_view).empty?,
diff --git a/app/views/katello/api/v2/content_facet/base.json.rabl b/app/views/katello/api/v2/content_facet/base.json.rabl
index 399bf8b278a..bcff2aa2103 100644
--- a/app/views/katello/api/v2/content_facet/base.json.rabl
+++ b/app/views/katello/api/v2/content_facet/base.json.rabl
@@ -14,6 +14,7 @@ child :content_view_environments => :content_view_environments do
id: cve.content_view&.id,
name: cve.content_view&.name,
composite: cve.content_view&.composite,
+ rolling: cve.content_view&.rolling,
content_view_version: cve.content_view_version&.version,
content_view_version_id: cve.content_view_version&.id,
content_view_version_latest: cve.content_view_version&.latest?,
@@ -46,6 +47,7 @@ node :content_view do |content_facet|
:id => content_view.id,
:name => content_view.name,
:composite => content_view.composite?,
+ :rolling => content_view.rolling?,
}
end
end
diff --git a/app/views/katello/api/v2/content_views/base.json.rabl b/app/views/katello/api/v2/content_views/base.json.rabl
index 21548d18200..ac094008873 100644
--- a/app/views/katello/api/v2/content_views/base.json.rabl
+++ b/app/views/katello/api/v2/content_views/base.json.rabl
@@ -2,6 +2,7 @@ extends 'katello/api/v2/common/identifier'
extends 'katello/api/v2/common/org_reference'
attributes :composite
+attributes :rolling
attributes :component_ids, :duplicate_repositories_to_publish
attributes :default
attributes :version_count
diff --git a/app/views/katello/api/v2/hosts/base.json.rabl b/app/views/katello/api/v2/hosts/base.json.rabl
index 4bdf894928d..5a53e849348 100644
--- a/app/views/katello/api/v2/hosts/base.json.rabl
+++ b/app/views/katello/api/v2/hosts/base.json.rabl
@@ -21,6 +21,7 @@ if @facet
:id => content_view.id,
:name => content_view.name,
:composite => content_view.composite?,
+ :rolling => content_view.rolling?,
}
end
end
diff --git a/app/views/katello/api/v2/organizations/show.json.rabl b/app/views/katello/api/v2/organizations/show.json.rabl
index 20c14715266..220db07d02a 100644
--- a/app/views/katello/api/v2/organizations/show.json.rabl
+++ b/app/views/katello/api/v2/organizations/show.json.rabl
@@ -32,10 +32,12 @@ node :default_content_view_id do |org|
end
node(:composite_content_views_count) { Katello::ContentView.readable&.in_organization(Organization.current)&.composite&.count }
+node(:rolling_content_views_count) { Katello::ContentView.readable&.in_organization(Organization.current)&.rolling&.count }
node(:content_view_components_count) do
Katello::ContentView.readable&.
in_organization(Organization.current)&.
non_composite&.
+ non_rolling&.
non_default&.
ignore_generated&.count
end
diff --git a/db/migrate/20241022122325_add_rolling_to_katello_content_views.rb b/db/migrate/20241022122325_add_rolling_to_katello_content_views.rb
new file mode 100644
index 00000000000..fb9969bfa50
--- /dev/null
+++ b/db/migrate/20241022122325_add_rolling_to_katello_content_views.rb
@@ -0,0 +1,5 @@
+class AddRollingToKatelloContentViews < ActiveRecord::Migration[6.1]
+ def change
+ add_column :katello_content_views, :rolling, :boolean, :default => false
+ end
+end
diff --git a/test/actions/katello/content_view_test.rb b/test/actions/katello/content_view_test.rb
index c299b85ebda..94dd32a97dd 100644
--- a/test/actions/katello/content_view_test.rb
+++ b/test/actions/katello/content_view_test.rb
@@ -99,6 +99,211 @@ class PublishTest < TestBase
end
end
+ class RefreshRollingRepoTest < TestBase
+ let(:action_class) { ::Actions::Katello::ContentView::RefreshRollingRepo }
+ let(:content_view) { katello_content_views(:rolling_view) }
+ let(:repository_deb) { katello_repositories(:debian_10_amd64) }
+ let(:library) { katello_environments(:library) }
+ let(:clone_deb) do
+ FactoryBot.create :katello_repository,
+ root: repository_deb.root,
+ library_instance: repository_deb,
+ content_view_version: content_view.versions.first,
+ environment: library
+ end
+
+ before do
+ repository_deb.version_href = 'foo'
+ repository_deb.publication_href = 'bar'
+ repository_deb.save!
+ clone_deb.save!
+ end
+
+ it 'plans' do
+ action.stubs(:task).returns(success_task)
+ refute_equal repository_deb.version_href, clone_deb.version_href
+
+ plan_action(action, clone_deb)
+
+ assert_action_planned_with action, ::Actions::Pulp3::Repository::RefreshDistribution, clone_deb, SmartProxy.pulp_primary
+ assert_action_planned_with action, ::Actions::Katello::Repository::IndexContent, id: clone_deb.id, source_repository_id: repository_deb.id
+ end
+
+ it 'triggers with sync' do
+ sync_action = create_action ::Actions::Katello::Repository::Sync
+ sync_action.stubs(:task).returns(success_task)
+
+ plan_action(sync_action, repository_deb)
+
+ assert_action_planned_with sync_action, action_class, clone_deb
+ end
+
+ it 'triggers with upload_files' do
+ upload_action = create_action ::Actions::Katello::Repository::UploadFiles
+ upload_action.stubs(:task).returns(success_task)
+ upload_action.stubs(:prepare_tmp_files).returns([{path: 'some/path'}])
+
+ plan_action(upload_action, repository_deb, [{path: 'nowhere'}])
+
+ assert_action_planned_with upload_action, action_class, clone_deb
+ end
+
+ it 'triggers with import_upload' do
+ import_action = create_action ::Actions::Katello::Repository::ImportUpload
+ import_action.stubs(:task).returns(success_task)
+ file = File.join(::Katello::Engine.root, 'test', 'fixtures', 'files', 'frigg_1.0_ppc64.deb')
+ #action.expects(:action_subject).with(custom_repository)
+
+ plan_action import_action, repository_deb, [{:path => file, :filename => 'frigg_1.0_ppc64.deb'}]
+
+ assert_action_planned_with import_action, action_class, clone_deb
+ end
+
+ it 'updates pulp_hrefs' do
+ last_changed = DateTime.new(2024, 12, 2.5)
+ DateTime.stubs(:now).returns(last_changed)
+ action_class.any_instance.expects(:plan_action).twice
+
+ ForemanTasks.sync_task(action_class, clone_deb)
+
+ clone_deb.reload
+ assert_equal repository_deb.version_href, clone_deb.version_href
+ assert_equal repository_deb.publication_href, clone_deb.publication_href
+ assert_equal repository_deb.content_id, clone_deb.content_id
+ assert_equal last_changed, clone_deb.last_contents_changed
+ end
+ end
+
+ class AddRollingRepoCloneTest < TestBase
+ let(:action_class) { ::Actions::Katello::ContentView::AddRollingRepoClone }
+ let(:content_view) { katello_content_views(:rolling_view) }
+ let(:repository_rpm) { katello_repositories(:fedora_17_x86_64) }
+ let(:repository_deb) { katello_repositories(:debian_10_amd64) }
+ let(:library) { katello_environments(:library) }
+ let(:clone_rpm) do
+ FactoryBot.create :katello_repository,
+ root: repository_rpm.root,
+ content_view_version: content_view.versions.first,
+ environment: library
+ end
+ let(:clone_deb) do
+ FactoryBot.create :katello_repository,
+ root: repository_deb.root,
+ content_view_version: content_view.versions.first,
+ environment: library
+ end
+ let(:cv_env) { content_view.content_view_environment(library) }
+
+ before do
+ [repository_rpm, repository_deb].each do |repository|
+ repository.version_href = 'foo'
+ repository.publication_href = 'bar'
+ repository.save!
+ end
+ end
+
+ it 'plans multiple' do
+ action.stubs(:task).returns(success_task)
+
+ Katello::Repository.any_instance.expects(:build_clone).returns(clone_deb)
+ Katello::Repository.any_instance.expects(:build_clone).returns(clone_rpm)
+ plan_action(action, content_view, [repository_rpm.id, repository_deb.id])
+
+ assert_action_planned_with action, ::Actions::Katello::ContentView::RefreshRollingRepo, clone_rpm
+ assert_action_planned_with action, ::Actions::Katello::ContentView::RefreshRollingRepo, clone_deb
+
+ assert_action_planned_with action, ::Actions::Candlepin::Environment::AddContentToEnvironment,
+ view_env_cp_id: cv_env.cp_id, content_id: repository_rpm.content_id
+ assert_action_planned_with action, ::Actions::Candlepin::Environment::AddContentToEnvironment,
+ view_env_cp_id: cv_env.cp_id, content_id: repository_deb.content_id
+ end
+
+ it 'plan refresh for existing' do
+ clone_deb.library_instance = repository_deb
+ clone_deb.version_href = 'some_version'
+ clone_deb.publication_href = 'some_publication'
+ clone_deb.save!
+
+ refute_equal repository_deb.version_href, clone_deb.version_href
+ refute_equal repository_deb.publication_href, clone_deb.publication_href
+ # double-add
+ plan_action(action, content_view, [repository_deb.id])
+
+ assert_equal 1, content_view.get_repo_clone(library, repository_deb).count
+ assert_action_planned_with action, ::Actions::Katello::ContentView::RefreshRollingRepo, clone_deb
+ assert_action_planned_with action, ::Actions::Candlepin::Environment::AddContentToEnvironment,
+ view_env_cp_id: cv_env.cp_id, content_id: repository_deb.content_id
+ end
+
+ it 'plans nothing' do
+ plan_action(action, content_view, [])
+
+ refute_action_planned action, ::Actions::Katello::ContentView::RefreshRollingRepo
+ refute_action_planned action, ::Actions::Candlepin::Environment::AddContentToEnvironment
+ end
+ end
+
+ class RemoveRollingRepoCloneTest < TestBase
+ let(:action_class) { ::Actions::Katello::ContentView::RemoveRollingRepoClone }
+ let(:content_view) { katello_content_views(:rolling_view) }
+ let(:repository_rpm) { katello_repositories(:fedora_17_x86_64) }
+ let(:repository_deb) { katello_repositories(:debian_10_amd64) }
+ let(:library) { katello_environments(:library) }
+ let(:clone_rpm) do
+ FactoryBot.create :katello_repository,
+ root: repository_rpm.root,
+ library_instance: repository_rpm,
+ content_view_version: content_view.versions.first,
+ environment: library
+ end
+ let(:clone_deb) do
+ FactoryBot.create :katello_repository,
+ root: repository_deb.root,
+ library_instance: repository_deb,
+ content_view_version: content_view.versions.first,
+ environment: library
+ end
+ let(:primary) { SmartProxy.pulp_primary }
+
+ before do
+ [repository_rpm, repository_deb].each do |repository|
+ repository.version_href = 'foo'
+ repository.publication_href = 'bar'
+ repository.save!
+ end
+ end
+
+ it 'plans remove multiple' do
+ clone_rpm.save!
+ clone_deb.save!
+
+ plan_action(action, content_view, [repository_rpm.id, repository_deb.id])
+
+ assert_action_planned_with action, ::Actions::Pulp3::Repository::DeleteDistributions, clone_rpm.id, primary
+ assert_action_planned_with action, ::Actions::Pulp3::Repository::DeleteDistributions, clone_deb.id, primary
+
+ cv_env = content_view.content_view_environment(library)
+ assert_action_planned_with action, ::Actions::Candlepin::Environment::SetContent, content_view, library, cv_env
+ end
+
+ it 'plan ignores gone repo' do
+ clone_rpm.destroy
+
+ plan_action(action, content_view, [repository_rpm.id])
+
+ refute_action_planned action, ::Actions::Pulp3::Repository::DeleteDistributions
+
+ cv_env = content_view.content_view_environment(library)
+ assert_action_planned_with action, ::Actions::Candlepin::Environment::SetContent, content_view, library, cv_env
+ end
+
+ it 'plans nothing' do
+ plan_action(action, content_view, [])
+ refute_action_planned action, ::Actions::Pulp3::Repository::DeleteDistributions
+ assert_action_planned action, ::Actions::Candlepin::Environment::SetContent
+ end
+ end
+
class PromoteToEnvironmentTest < TestBase
let(:action_class) { ::Actions::Katello::ContentView::PromoteToEnvironment }
@@ -393,6 +598,25 @@ class UpdateTest < TestBase
end
end
+ class UpdateRollingTest < TestBase
+ let(:action_class) { ::Actions::Katello::ContentView::Update }
+ let(:add_rolling_repo_action_class) { ::Actions::Katello::ContentView::AddRollingRepoClone }
+ let(:remove_rolling_repo_action_class) { ::Actions::Katello::ContentView::RemoveRollingRepoClone }
+ let(:content_view) { katello_content_views(:rolling_view) }
+ let(:repository) { katello_repositories(:rhel_6_x86_64) }
+ let(:action) { create_action action_class }
+
+ it 'plans add/remove repo' do
+ action.expects(:action_subject).with(content_view)
+ old_repo_ids = content_view.repository_ids
+
+ plan_action action, content_view, 'repository_ids' => [repository.id]
+
+ assert_action_planned_with action, add_rolling_repo_action_class, content_view, [repository.id]
+ assert_action_planned_with action, remove_rolling_repo_action_class, content_view, old_repo_ids
+ end
+ end
+
class DestroyTest < TestBase
let(:action_class) { ::Actions::Katello::ContentView::Destroy }
diff --git a/test/controllers/api/v2/content_views_controller_test.rb b/test/controllers/api/v2/content_views_controller_test.rb
index 98cc4e1300e..14bbfca2e87 100644
--- a/test/controllers/api/v2/content_views_controller_test.rb
+++ b/test/controllers/api/v2/content_views_controller_test.rb
@@ -243,8 +243,8 @@ def test_update_repositories_strings
params = { :repository_ids => [repository.id.to_s] }
assert_sync_task(::Actions::Katello::ContentView::Update) do |_content_view, content_view_params|
- assert_equal content_view_params.key?(:repository_ids), true
- assert_equal content_view_params[:repository_ids], params[:repository_ids]
+ assert content_view_params.key?(:repository_ids)
+ assert_equal [repository.id], content_view_params[:repository_ids]
end
put :update, params: { :id => @library_dev_staging_view.id, :content_view => params }
diff --git a/test/factories/content_view_factory.rb b/test/factories/content_view_factory.rb
index a3043aad81a..21a7a0286fa 100644
--- a/test/factories/content_view_factory.rb
+++ b/test/factories/content_view_factory.rb
@@ -11,5 +11,9 @@
trait :import_only do
import_only { true }
end
+
+ trait :rolling do
+ rolling { true }
+ end
end
end
diff --git a/test/fixtures/models/katello_content_view_environments.yml b/test/fixtures/models/katello_content_view_environments.yml
index 7e55fc60f36..f1c418334ab 100644
--- a/test/fixtures/models/katello_content_view_environments.yml
+++ b/test/fixtures/models/katello_content_view_environments.yml
@@ -98,3 +98,13 @@ library_dev_view_acme:
content_view_version_id: <%= ActiveRecord::FixtureSet.identify(:library_dev_view_version) %>
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
+
+rolling_view_library:
+ name: Rolling view library environment
+ label: 'rolling_view_library'
+ cp_id: 14
+ environment_id: <%= ActiveRecord::FixtureSet.identify(:library) %>
+ content_view_id: <%= ActiveRecord::FixtureSet.identify(:rolling_view) %>
+ content_view_version_id: <%= ActiveRecord::FixtureSet.identify(:rolling_view_library_version) %>
+ created_at: <%= Time.now %>
+ updated_at: <%= Time.now %>
diff --git a/test/fixtures/models/katello_content_view_repositories.yml b/test/fixtures/models/katello_content_view_repositories.yml
index 7e80607c1b5..68009430e67 100644
--- a/test/fixtures/models/katello_content_view_repositories.yml
+++ b/test/fixtures/models/katello_content_view_repositories.yml
@@ -37,3 +37,7 @@ library_view_python:
import_only_view_fedora_17_x86_64:
content_view_id: <%= ActiveRecord::FixtureSet.identify(:import_only_view) %>
repository_id: <%= ActiveRecord::FixtureSet.identify(:fedora_17_x86_64) %>
+
+rolling_view_fedora_17_x86_64:
+ content_view_id: <%= ActiveRecord::FixtureSet.identify(:rolling_view) %>
+ repository_id: <%= ActiveRecord::FixtureSet.identify(:fedora_17_x86_64) %>
diff --git a/test/fixtures/models/katello_content_view_versions.yml b/test/fixtures/models/katello_content_view_versions.yml
index 4cfa9137446..b20d1d29f79 100644
--- a/test/fixtures/models/katello_content_view_versions.yml
+++ b/test/fixtures/models/katello_content_view_versions.yml
@@ -34,3 +34,6 @@ library_view_solve_deps_version:
content_view_id: <%= ActiveRecord::FixtureSet.identify(:library_view_solve_deps) %>
major: 1
+rolling_view_library_version:
+ content_view_id: <%= ActiveRecord::FixtureSet.identify(:rolling_view) %>
+ major: 1
diff --git a/test/fixtures/models/katello_content_views.yml b/test/fixtures/models/katello_content_views.yml
index 3197de439dd..663d2982b7a 100644
--- a/test/fixtures/models/katello_content_views.yml
+++ b/test/fixtures/models/katello_content_views.yml
@@ -204,3 +204,14 @@ library_view_solve_deps:
created_at: <%= Time.now %>
updated_at: <%= Time.now %>
organization_id: <%= ActiveRecord::FixtureSet.identify(:empty_organization) %>
+
+rolling_view:
+ name: Rolling CV
+ description: A rolling content view
+ label: 'rolling_cv'
+ default: false
+ rolling: true
+ next_version: 2
+ created_at: <%= Time.now %>
+ updated_at: <%= Time.now %>
+ organization_id: <%= ActiveRecord::FixtureSet.identify(:empty_organization) %>
diff --git a/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json b/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json
index 84f7f14b41b..dd303b6f2df 100644
--- a/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json
+++ b/webpack/scenes/ContentViews/Copy/__tests__/contentViewCopyResult.fixtures.json
@@ -1,6 +1,7 @@
{
"content_host_count": 0,
"composite": false,
+ "rolling": false,
"component_ids": [],
"default": false,
"version_count": 0,
diff --git a/webpack/scenes/ContentViews/Create/CreateContentViewForm.js b/webpack/scenes/ContentViews/Create/CreateContentViewForm.js
index 62b594b160c..03e602fb435 100644
--- a/webpack/scenes/ContentViews/Create/CreateContentViewForm.js
+++ b/webpack/scenes/ContentViews/Create/CreateContentViewForm.js
@@ -18,6 +18,7 @@ const CreateContentViewForm = ({ setModalOpen }) => {
const [description, setDescription] = useState('');
const [composite, setComposite] = useState(false);
const [component, setComponent] = useState(true);
+ const [rolling, setRolling] = useState(false);
const [autoPublish, setAutoPublish] = useState(false);
const [dependencies, setDependencies] = useState(false);
const [redirect, setRedirect] = useState(false);
@@ -56,7 +57,8 @@ const CreateContentViewForm = ({ setModalOpen }) => {
label,
description,
composite,
- solve_dependencies: dependencies,
+ rolling,
+ solve_dependencies: (dependencies && !(rolling || composite)),
auto_publish: (autoPublish && composite),
}));
};
@@ -70,7 +72,11 @@ const CreateContentViewForm = ({ setModalOpen }) => {
if (redirect) {
const { id } = response;
- if (composite) { window.location.assign(`/content_views/${id}#/contentviews`); } else { window.location.assign(`/content_views/${id}#/repositories`); }
+ if (composite) {
+ window.location.assign(`/content_views/${id}#/contentviews`);
+ } else {
+ window.location.assign(`/content_views/${id}#/repositories`);
+ }
}
const submitDisabled = !name?.length || !label?.length || saving || redirect || labelValidated === 'error';
@@ -127,37 +133,51 @@ const CreateContentViewForm = ({ setModalOpen }) => {
-
+
}
+ icon={}
id="component"
- title={__('Content view')}
- onClick={() => { setComponent(true); setComposite(false); }}
+ title={__('Regular content view')}
+ onClick={() => { setComponent(true); setComposite(false); setRolling(false); }}
isSelected={component}
>
- {__('Single content view consisting of e.g. repositories')}
+ {__('Contains a set of versioned and optionally filtered repositories')}
-
+
}
+ icon={}
id="composite"
title={__('Composite content view')}
- onClick={() => { setComposite(true); setComponent(false); }}
+ onClick={() => { setComposite(true); setComponent(false); setRolling(false); }}
isSelected={composite}
>
- {__('Consisting of multiple content views')}
+ {__('Contains a set of regular content views')}
+
+
+
+ }
+ id="rolling"
+ title={__('Rolling content view')}
+ onClick={() => { setComposite(false); setComponent(false); setRolling(true); }}
+ isSelected={rolling}
+ >
+ {__('Contains a set of repositories that always contain the latest synced content')}
- {!composite &&
+ {!composite && !rolling &&
{
expect(getByText('Name')).toBeInTheDocument();
expect(getByText('Label')).toBeInTheDocument();
expect(getByText('Composite content view')).toBeInTheDocument();
- expect(getByText('Content view')).toBeInTheDocument();
+ expect(getByText('Regular content view')).toBeInTheDocument();
+ expect(getByText('Rolling content view')).toBeInTheDocument();
expect(getByText('Solve dependencies')).toBeInTheDocument();
expect(queryByText('Auto publish')).not.toBeInTheDocument();
diff --git a/webpack/scenes/ContentViews/Delete/__tests__/CvData.fixtures.json b/webpack/scenes/ContentViews/Delete/__tests__/CvData.fixtures.json
index 7542e9c7a68..c3b2cacb8aa 100644
--- a/webpack/scenes/ContentViews/Delete/__tests__/CvData.fixtures.json
+++ b/webpack/scenes/ContentViews/Delete/__tests__/CvData.fixtures.json
@@ -14,6 +14,7 @@
"results": [
{
"composite": false,
+ "rolling": false,
"component_ids": [],
"default": false,
"version_count": 4,
@@ -258,4 +259,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json b/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json
index dfac7a6ff42..ea7a03c055c 100644
--- a/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json
+++ b/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json
@@ -113,7 +113,8 @@
"content_view": {
"id": 20,
"name": "cv3",
- "composite": false
+ "composite": false,
+ "rolling": false
},
"lifecycle_environment": {
"id": 2,
@@ -138,4 +139,4 @@
}
}
]
-}
\ No newline at end of file
+}
diff --git a/webpack/scenes/ContentViews/Delete/__tests__/cvDetails.fixtures.json b/webpack/scenes/ContentViews/Delete/__tests__/cvDetails.fixtures.json
index 06f50da1803..9665eb21904 100644
--- a/webpack/scenes/ContentViews/Delete/__tests__/cvDetails.fixtures.json
+++ b/webpack/scenes/ContentViews/Delete/__tests__/cvDetails.fixtures.json
@@ -1,6 +1,7 @@
{
"content_host_count": 1,
"composite": false,
+ "rolling": false,
"component_ids": [],
"default": false,
"version_count": 4,
@@ -245,4 +246,4 @@
},
"duplicate_repositories_to_publish": [],
"errors": null
-}
\ No newline at end of file
+}
diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/compositeCVDetails.fixtures.json b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/compositeCVDetails.fixtures.json
index 5feb78ebdff..3f625a0c202 100644
--- a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/compositeCVDetails.fixtures.json
+++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/compositeCVDetails.fixtures.json
@@ -1,6 +1,7 @@
{
"content_host_count": 0,
"composite": true,
+ "rolling": false,
"component_ids": [
5,
7
@@ -390,4 +391,4 @@
"promote_or_remove_content_views": true
},
"errors": null
-}
\ No newline at end of file
+}
diff --git a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json
index 9dc0975d74b..08c20182d60 100644
--- a/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json
+++ b/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/publishedContentViewDetails.fixtures.json
@@ -1,6 +1,7 @@
{
"content_host_count": 0,
"composite": false,
+ "rolling": false,
"component_ids": [],
"default": false,
"version_count": 33,
@@ -210,4 +211,4 @@
},
"duplicate_repositories_to_publish": [],
"errors": null
-}
\ No newline at end of file
+}
diff --git a/webpack/scenes/ContentViews/Details/ContentViewDetails.js b/webpack/scenes/ContentViews/Details/ContentViewDetails.js
index 9423f4e458d..53f3ca9c0ad 100644
--- a/webpack/scenes/ContentViews/Details/ContentViewDetails.js
+++ b/webpack/scenes/ContentViews/Details/ContentViewDetails.js
@@ -81,31 +81,17 @@ export default () => {
if (status === STATUS.PENDING) return ();
if (status === STATUS.ERROR) return ();
- const dropDownItems = [
- {
- setCopying(true);
- }}
- >
- {__('Copy')}
- ,
- {
- setDeleting(true);
- }}
- >
- {__('Delete')}
- ,
- ];
-
const {
- name, composite, permissions, environments, versions,
+ name, composite, rolling, permissions, environments, versions,
generated_for: generatedFor, import_only: importOnly,
} = details;
+
+ const dropDownItems = [];
+ if (!rolling) {
+ dropDownItems.push( { setCopying(true); }} > {__('Copy')});
+ }
+ dropDownItems.push( { setDeleting(true); }} > {__('Delete')});
+
const generatedContentView = generatedFor !== 'none';
const detailsTab = {
key: 'details',
@@ -141,11 +127,11 @@ export default () => {
/* eslint-disable no-nested-ternary */
const tabs = [
detailsTab,
- versionsTab,
+ ...(rolling ? [] : [versionsTab]),
...(composite ? [contentViewsTab] :
- ((importOnly || generatedContentView) ?
+ ((importOnly || generatedContentView || rolling) ?
[repositoriesTab] : [repositoriesTab, filtersTab])),
- historyTab,
+ ...(rolling ? [] : [historyTab]),
];
/* eslint-enable no-nested-ternary */
@@ -162,7 +148,11 @@ export default () => {
-
+
@@ -170,7 +160,8 @@ export default () => {
- {hasPermission(permissions, 'publish_content_views') &&
+ {!rolling &&
+ hasPermission(permissions, 'publish_content_views') &&
+
+
+
+
+
+
+
+ }
+ />
+
+
+
diff --git a/webpack/scenes/ContentViews/components/contentViewIcon.scss b/webpack/scenes/ContentViews/components/contentViewIcon.scss
index 21e2710950b..e3f24ec57fb 100644
--- a/webpack/scenes/ContentViews/components/contentViewIcon.scss
+++ b/webpack/scenes/ContentViews/components/contentViewIcon.scss
@@ -17,4 +17,9 @@
.svg-icon-component {
margin: 0 9px;
display: block;
-}
\ No newline at end of file
+}
+
+.svg-icon-rolling {
+ margin: 0 9px;
+ display: block;
+}
diff --git a/webpack/scenes/ContentViews/expansions/DetailsExpansion.js b/webpack/scenes/ContentViews/expansions/DetailsExpansion.js
index 060bdddb944..e17a05a8541 100644
--- a/webpack/scenes/ContentViews/expansions/DetailsExpansion.js
+++ b/webpack/scenes/ContentViews/expansions/DetailsExpansion.js
@@ -5,12 +5,15 @@ import RelatedCompositeContentViewsModal from './RelatedCompositeContentViewsMod
import RelatedContentViewComponentsModal from './RelatedContentViewComponentsModal';
const DetailsExpansion = ({
- cvId, cvName, cvComposite, activationKeys, hosts, relatedCVCount, relatedCompositeCVs,
+ cvId, cvName, cvComposite, cvRolling, activationKeys, hosts, relatedCVCount, relatedCompositeCVs,
}) => {
const activationKeyCount = activationKeys.length;
const hostCount = hosts.length;
const relatedContentViewModal = () => {
+ if (cvRolling) {
+ return <>>;
+ }
if (cvComposite) {
return (
<>
@@ -49,6 +52,7 @@ DetailsExpansion.propTypes = {
hosts: PropTypes.arrayOf(PropTypes.shape({})),
cvName: PropTypes.string,
cvComposite: PropTypes.bool,
+ cvRolling: PropTypes.bool,
relatedCompositeCVs: PropTypes.arrayOf(PropTypes.shape({})),
relatedCVCount: PropTypes.number,
};
@@ -58,6 +62,7 @@ DetailsExpansion.defaultProps = {
hosts: [],
cvName: '',
cvComposite: false,
+ cvRolling: false,
relatedCompositeCVs: [],
relatedCVCount: 0,