Commit 86eaf1c6 authored by David Fernandez's avatar David Fernandez

Merge branch 'debian_crud_distributions' into 'master'

Debian CRUD distribution endpoints

See merge request gitlab-org/gitlab!62017
parents f8f7aaf4 7517d255
...@@ -95,6 +95,14 @@ module Packages ...@@ -95,6 +95,14 @@ module Packages
mount_file_store_uploader Packages::Debian::DistributionReleaseFileUploader mount_file_store_uploader Packages::Debian::DistributionReleaseFileUploader
def component_names
components.pluck(:name).sort
end
def architecture_names
architectures.pluck(:name).sort
end
def needs_update? def needs_update?
!file.exists? || time_duration_expired? !file.exists? || time_duration_expired?
end end
......
...@@ -38,14 +38,19 @@ module Packages ...@@ -38,14 +38,19 @@ module Packages
append_errors(distribution) append_errors(distribution)
return error unless errors.empty? return error unless errors.empty?
distribution.transaction do result = distribution.transaction do
if distribution.save next unless distribution.save
create_components
create_architectures create_components
create_architectures
success success
end end
end || error
result ||= error
::Packages::Debian::GenerateDistributionWorker.perform_async(distribution.class.container_type, distribution.reset.id) if result.success?
result
end end
def create_components def create_components
......
# frozen_string_literal: true
module Packages
module Debian
class DestroyDistributionService
def initialize(distribution)
@distribution = distribution
end
def execute
destroy_distribution
end
private
def destroy_distribution
if @distribution.destroy
success
else
error("Unable to destroy Debian #{@distribution.model_name.human.downcase}")
end
end
def success
ServiceResponse.success
end
def error(message)
ServiceResponse.error(message: message, payload: { distribution: @distribution })
end
end
end
end
...@@ -31,7 +31,7 @@ module Packages ...@@ -31,7 +31,7 @@ module Packages
end end
def update_distribution def update_distribution
distribution.transaction do result = distribution.transaction do
if distribution.update(params) if distribution.update(params)
update_components if components update_components if components
update_architectures if architectures update_architectures if architectures
...@@ -41,7 +41,13 @@ module Packages ...@@ -41,7 +41,13 @@ module Packages
append_errors(distribution) append_errors(distribution)
error error
end end
end || error end
result ||= error
::Packages::Debian::GenerateDistributionWorker.perform_async(distribution.class.container_type, distribution.id) if result.success?
result
end end
def update_components def update_components
......
...@@ -228,6 +228,7 @@ module API ...@@ -228,6 +228,7 @@ module API
mount ::API::PagesDomains mount ::API::PagesDomains
mount ::API::ProjectClusters mount ::API::ProjectClusters
mount ::API::ProjectContainerRepositories mount ::API::ProjectContainerRepositories
mount ::API::ProjectDebianDistributions
mount ::API::ProjectEvents mount ::API::ProjectEvents
mount ::API::ProjectExport mount ::API::ProjectExport
mount ::API::ProjectImport mount ::API::ProjectImport
......
# frozen_string_literal: true
module API
module Concerns
module Packages
module DebianDistributionEndpoints
extend ActiveSupport::Concern
included do
include PaginationParams
feature_category :package_registry
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
include ::API::Helpers::Authentication
namespace 'debian_distributions' do
helpers do
params :optional_distribution_params do
optional :suite, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Suite'
optional :origin, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Origin'
optional :label, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Label'
optional :version, type: String, regexp: Gitlab::Regex.debian_version_regex, desc: 'The Debian Version'
optional :description, type: String, desc: 'The Debian Description'
optional :valid_time_duration_seconds, type: Integer, desc: 'The duration before the Release file should be considered expired by the client'
optional :components, type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
regexp: Gitlab::Regex.debian_component_regex,
desc: 'The list of Components'
optional :architectures, type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
regexp: Gitlab::Regex.debian_architecture_regex,
desc: 'The list of Architectures'
end
end
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
end
content_type :json, 'application/json'
format :json
# POST {projects|groups}/:id/debian_distributions
desc 'Create a Debian Distribution' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
post '/' do
authorize_create_package!(project_or_group)
distribution_params = declared_params(include_missing: false)
result = ::Packages::Debian::CreateDistributionService.new(project_or_group, current_user, distribution_params).execute
distribution = result.payload[:distribution]
if result.success?
present distribution, with: ::API::Entities::Packages::Debian::Distribution
else
render_validation_error!(distribution)
end
end
# GET {projects|groups}/:id/debian_distributions
desc 'Get a list of Debian Distributions' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
use :pagination
optional :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
get '/' do
distribution_params = declared_params(include_missing: false)
distributions = ::Packages::Debian::DistributionsFinder.new(project_or_group, distribution_params).execute
present paginate(distributions), with: ::API::Entities::Packages::Debian::Distribution
end
# GET {projects|groups}/:id/debian_distributions/:codename
desc 'Get a Debian Distribution' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
end
get '/:codename' do
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
present distribution, with: ::API::Entities::Packages::Debian::Distribution
end
# PUT {projects|groups}/:id/debian_distributions/:codename
desc 'Update a Debian Distribution' do
detail 'This feature was introduced in 14.0'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
put '/:codename' do
authorize_create_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
distribution_params = declared_params(include_missing: false).except(:codename)
result = ::Packages::Debian::UpdateDistributionService.new(distribution, distribution_params).execute
distribution = result.payload[:distribution]
if result.success?
present distribution, with: ::API::Entities::Packages::Debian::Distribution
else
render_validation_error!(distribution)
end
end
# DELETE {projects|groups}/:id/debian_distributions/:codename
desc 'Delete a Debian Distribution' do
detail 'This feature was introduced in 14.0'
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
use :optional_distribution_params
end
delete '/:codename' do
authorize_destroy_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
accepted! if distribution.destroy
render_api_error!('Failed to delete distribution', 400)
end
end
end
end
end
end
end
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module API module API
module Concerns module Concerns
module Packages module Packages
module DebianEndpoints module DebianPackageEndpoints
extend ActiveSupport::Concern extend ActiveSupport::Concern
DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze
...@@ -32,23 +32,17 @@ module API ...@@ -32,23 +32,17 @@ module API
helpers ::API::Helpers::PackagesHelpers helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers helpers ::API::Helpers::Packages::BasicAuthHelpers
include ::API::Helpers::Authentication
format :txt namespace 'packages/debian' do
content_type :txt, 'text/plain' authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
rescue_from ArgumentError do |e| .sent_through(:http_basic_auth)
render_api_error!(e.message, 400) end
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
before do format :txt
require_packages_enabled! content_type :txt, 'text/plain'
end
namespace 'packages/debian' do
params do params do
requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex
end end
...@@ -59,7 +53,7 @@ module API ...@@ -59,7 +53,7 @@ module API
detail 'This feature was introduced in GitLab 13.5' detail 'This feature was introduced in GitLab 13.5'
end end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true route_setting :authentication, authenticate_non_public: true
get 'Release.gpg' do get 'Release.gpg' do
not_found! not_found!
end end
...@@ -69,7 +63,7 @@ module API ...@@ -69,7 +63,7 @@ module API
detail 'This feature was introduced in GitLab 13.5' detail 'This feature was introduced in GitLab 13.5'
end end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true route_setting :authentication, authenticate_non_public: true
get 'Release' do get 'Release' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286 # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Release' 'TODO Release'
...@@ -80,7 +74,7 @@ module API ...@@ -80,7 +74,7 @@ module API
detail 'This feature was introduced in GitLab 13.5' detail 'This feature was introduced in GitLab 13.5'
end end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true route_setting :authentication, authenticate_non_public: true
get 'InRelease' do get 'InRelease' do
not_found! not_found!
end end
...@@ -96,7 +90,7 @@ module API ...@@ -96,7 +90,7 @@ module API
detail 'This feature was introduced in GitLab 13.5' detail 'This feature was introduced in GitLab 13.5'
end end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true route_setting :authentication, authenticate_non_public: true
get 'Packages' do get 'Packages' do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286 # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO Packages' 'TODO Packages'
...@@ -119,7 +113,7 @@ module API ...@@ -119,7 +113,7 @@ module API
detail 'This feature was introduced in GitLab 13.5' detail 'This feature was introduced in GitLab 13.5'
end end
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth, authenticate_non_public: true route_setting :authentication, authenticate_non_public: true
get ':file_name', requirements: FILE_NAME_REQUIREMENTS do get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
# https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286 # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
'TODO File' 'TODO File'
......
...@@ -7,6 +7,14 @@ module API ...@@ -7,6 +7,14 @@ module API
end end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
before do before do
require_packages_enabled! require_packages_enabled!
...@@ -16,7 +24,7 @@ module API ...@@ -16,7 +24,7 @@ module API
end end
namespace ':id/-' do namespace ':id/-' do
include ::API::Concerns::Packages::DebianEndpoints include ::API::Concerns::Packages::DebianPackageEndpoints
end end
end end
end end
......
...@@ -7,7 +7,15 @@ module API ...@@ -7,7 +7,15 @@ module API
end end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
after_validation do
require_packages_enabled! require_packages_enabled!
not_found! unless ::Feature.enabled?(:debian_packages, user_project) not_found! unless ::Feature.enabled?(:debian_packages, user_project)
...@@ -16,13 +24,20 @@ module API ...@@ -16,13 +24,20 @@ module API
end end
namespace ':id' do namespace ':id' do
include ::API::Concerns::Packages::DebianEndpoints helpers do
def project_or_group
user_project
end
end
include ::API::Concerns::Packages::DebianPackageEndpoints
params do params do
requires :file_name, type: String, desc: 'The file name' requires :file_name, type: String, desc: 'The file name'
end end
namespace 'packages/debian/:file_name', requirements: FILE_NAME_REQUIREMENTS do namespace 'packages/debian/:file_name', requirements: FILE_NAME_REQUIREMENTS do
format :txt
content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE content_type :json, Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE
# PUT {projects|groups}/:id/packages/debian/:file_name # PUT {projects|groups}/:id/packages/debian/:file_name
...@@ -35,8 +50,6 @@ module API ...@@ -35,8 +50,6 @@ module API
authorize_upload!(authorized_user_project) authorize_upload!(authorized_user_project)
bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:debian_max_file_size, params[:file].size) bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:debian_max_file_size, params[:file].size)
track_package_event('push_package', :debian, user: current_user, project: authorized_user_project, namespace: authorized_user_project.namespace)
file_params = { file_params = {
file: params['file'], file: params['file'],
file_name: params['file_name'], file_name: params['file_name'],
...@@ -52,6 +65,7 @@ module API ...@@ -52,6 +65,7 @@ module API
::Packages::Debian::ProcessChangesWorker.perform_async(package_file.id, current_user.id) # rubocop:disable CodeReuse/Worker ::Packages::Debian::ProcessChangesWorker.perform_async(package_file.id, current_user.id) # rubocop:disable CodeReuse/Worker
end end
track_package_event('push_package', :debian, user: current_user, project: authorized_user_project, namespace: authorized_user_project.namespace)
created! created!
rescue ObjectStorage::RemoteStoreError => e rescue ObjectStorage::RemoteStoreError => e
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id }) Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id })
......
# frozen_string_literal: true
module API
module Entities
module Packages
module Debian
class Distribution < Grape::Entity
expose :id
expose :codename
expose :suite
expose :origin
expose :label
expose :version
expose :description
expose :valid_time_duration_seconds
expose :component_names, as: :components
expose :architecture_names, as: :architectures
end
end
end
end
end
# frozen_string_literal: true
module API
class ProjectDebianDistributions < ::API::Base
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
after_validation do
require_packages_enabled!
not_found! unless ::Feature.enabled?(:debian_packages, user_project)
authorize_read_package!
end
namespace ':id' do
helpers do
def project_or_group
user_project
end
end
include ::API::Concerns::Packages::DebianDistributionEndpoints
end
end
end
end
...@@ -7,33 +7,33 @@ RSpec.describe API::DebianGroupPackages do ...@@ -7,33 +7,33 @@ RSpec.describe API::DebianGroupPackages do
include_context 'Debian repository shared context', :group, false do include_context 'Debian repository shared context', :group, false do
describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release.gpg' do describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release.gpg' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/Release.gpg" } let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/Release.gpg" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release' do describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/Release" } let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/Release" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Release' it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Release$/
end end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/InRelease' do describe 'GET groups/:id/-/packages/debian/dists/*distribution/InRelease' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/InRelease" } let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/InRelease" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution}/#{component}/binary-#{architecture}/Packages" } let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component}/binary-#{architecture}/Packages" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Packages' it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Packages$/
end end
describe 'GET groups/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name' do describe 'GET groups/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name' do
let(:url) { "/groups/#{container.id}/-/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" } let(:url) { "/groups/#{container.id}/-/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO File' it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO File$/
end end
end end
end end
...@@ -7,33 +7,33 @@ RSpec.describe API::DebianProjectPackages do ...@@ -7,33 +7,33 @@ RSpec.describe API::DebianProjectPackages do
include_context 'Debian repository shared context', :project, true do include_context 'Debian repository shared context', :project, true do
describe 'GET projects/:id/packages/debian/dists/*distribution/Release.gpg' do describe 'GET projects/:id/packages/debian/dists/*distribution/Release.gpg' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/Release.gpg" } let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/Release.gpg" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end end
describe 'GET projects/:id/packages/debian/dists/*distribution/Release' do describe 'GET projects/:id/packages/debian/dists/*distribution/Release' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/Release" } let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/Release" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Release' it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Release$/
end end
describe 'GET projects/:id/packages/debian/dists/*distribution/InRelease' do describe 'GET projects/:id/packages/debian/dists/*distribution/InRelease' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/InRelease" } let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/InRelease" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found it_behaves_like 'Debian repository read endpoint', 'GET request', :not_found
end end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution}/#{component}/binary-#{architecture}/Packages" } let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component}/binary-#{architecture}/Packages" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO Packages' it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO Packages$/
end end
describe 'GET projects/:id/packages/debian/pool/:component/:letter/:source_package/:file_name' do describe 'GET projects/:id/packages/debian/pool/:component/:letter/:source_package/:file_name' do
let(:url) { "/projects/#{container.id}/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" } let(:url) { "/projects/#{container.id}/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, 'TODO File' it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^TODO File$/
end end
describe 'PUT projects/:id/packages/debian/:file_name' do describe 'PUT projects/:id/packages/debian/:file_name' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::ProjectDebianDistributions do
include HttpBasicAuthHelpers
include WorkhorseHelpers
include_context 'Debian repository shared context', :project, true do
describe 'POST projects/:id/debian_distributions' do
let(:method) { :post }
let(:url) { "/projects/#{container.id}/debian_distributions" }
let(:api_params) { { 'codename': 'my-codename' } }
it_behaves_like 'Debian repository write endpoint', 'POST distribution request', :created, /^{.*"codename":"my-codename",.*"components":\["main"\],.*"architectures":\["all","amd64"\]/, authenticate_non_public: false
context 'with invalid parameters' do
let(:api_params) { { codename: distribution.codename } }
it_behaves_like 'Debian repository write endpoint', 'GET request', :bad_request, /^{"message":{"codename":\["has already been taken"\]}}$/, authenticate_non_public: false
end
end
describe 'GET projects/:id/debian_distributions' do
let(:url) { "/projects/#{container.id}/debian_distributions" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^\[{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/, authenticate_non_public: false
end
describe 'GET projects/:id/debian_distributions/:codename' do
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/, authenticate_non_public: false
end
describe 'PUT projects/:id/debian_distributions/:codename' do
let(:method) { :put }
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
let(:api_params) { { suite: 'my-suite' } }
it_behaves_like 'Debian repository write endpoint', 'PUT distribution request', :success, /^{.*"codename":"existing-codename",.*"suite":"my-suite",/, authenticate_non_public: false
context 'with invalid parameters' do
let(:api_params) { { suite: distribution.codename } }
it_behaves_like 'Debian repository write endpoint', 'GET request', :bad_request, /^{"message":{"suite":\["has already been taken as Codename"\]}}$/, authenticate_non_public: false
end
end
describe 'DELETE projects/:id/debian_distributions/:codename' do
let(:method) { :delete }
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
it_behaves_like 'Debian repository maintainer write endpoint', 'DELETE distribution request', :success, /^{\"message\":\"202 Accepted\"}$/, authenticate_non_public: false
context 'when destroy fails' do
before do
allow_next_found_instance_of(::Packages::Debian::ProjectDistribution) do |distribution|
expect(distribution).to receive(:destroy).and_return(false)
end
end
it_behaves_like 'Debian repository maintainer write endpoint', 'GET request', :bad_request, /^{"message":"Failed to delete distribution"}$/, authenticate_non_public: false
end
end
end
end
...@@ -4,8 +4,12 @@ require 'spec_helper' ...@@ -4,8 +4,12 @@ require 'spec_helper'
RSpec.describe Packages::Debian::CreateDistributionService do RSpec.describe Packages::Debian::CreateDistributionService do
RSpec.shared_examples 'Create Debian Distribution' do |expected_message, expected_components, expected_architectures| RSpec.shared_examples 'Create Debian Distribution' do |expected_message, expected_components, expected_architectures|
let_it_be(:container) { create(container_type) } # rubocop:disable Rails/SaveBang
it 'returns ServiceResponse', :aggregate_failures do it 'returns ServiceResponse', :aggregate_failures do
if expected_message.nil? if expected_message.nil?
expect(::Packages::Debian::GenerateDistributionWorker).to receive(:perform_async).with(container_type, an_instance_of(Integer))
expect { response } expect { response }
.to change { container.debian_distributions.klass.all.count } .to change { container.debian_distributions.klass.all.count }
.from(0).to(1) .from(0).to(1)
...@@ -18,6 +22,7 @@ RSpec.describe Packages::Debian::CreateDistributionService do ...@@ -18,6 +22,7 @@ RSpec.describe Packages::Debian::CreateDistributionService do
.and not_change { Packages::Debian::ProjectComponentFile.count } .and not_change { Packages::Debian::ProjectComponentFile.count }
.and not_change { Packages::Debian::GroupComponentFile.count } .and not_change { Packages::Debian::GroupComponentFile.count }
else else
expect(::Packages::Debian::GenerateDistributionWorker).not_to receive(:perform_async)
expect { response } expect { response }
.to not_change { container.debian_distributions.klass.all.count } .to not_change { container.debian_distributions.klass.all.count }
.and not_change { container.debian_distributions.count } .and not_change { container.debian_distributions.count }
...@@ -109,13 +114,13 @@ RSpec.describe Packages::Debian::CreateDistributionService do ...@@ -109,13 +114,13 @@ RSpec.describe Packages::Debian::CreateDistributionService do
let(:response) { subject.execute } let(:response) { subject.execute }
context 'within a projet' do context 'within a projet' do
let_it_be(:container) { create(:project) } let_it_be(:container_type) { :project }
it_behaves_like 'Debian Create Distribution Service' it_behaves_like 'Debian Create Distribution Service'
end end
context 'within a group' do context 'within a group' do
let_it_be(:container) { create(:group) } let_it_be(:container_type) { :group }
it_behaves_like 'Debian Create Distribution Service' it_behaves_like 'Debian Create Distribution Service'
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Debian::DestroyDistributionService do
RSpec.shared_examples 'Destroy Debian Distribution' do |expected_message|
it 'returns ServiceResponse', :aggregate_failures do
if expected_message.nil?
expect { response }
.to change { container.debian_distributions.klass.all.count }
.from(1).to(0)
.and change { container.debian_distributions.count }
.from(1).to(0)
.and change { component1.class.all.count }
.from(2).to(0)
.and change { architecture1.class.all.count }
.from(3).to(0)
.and change { component_file1.class.all.count }
.from(4).to(0)
else
expect { response }
.to not_change { container.debian_distributions.klass.all.count }
.and not_change { container.debian_distributions.count }
.and not_change { component1.class.all.count }
.and not_change { architecture1.class.all.count }
.and not_change { component_file1.class.all.count }
end
expect(response).to be_a(ServiceResponse)
expect(response.success?).to eq(expected_message.nil?)
expect(response.error?).to eq(!expected_message.nil?)
expect(response.message).to eq(expected_message)
if expected_message.nil?
expect(response.payload).to eq({})
else
expect(response.payload).to eq(distribution: distribution)
end
end
end
RSpec.shared_examples 'Debian Destroy Distribution Service' do |container_type, can_freeze|
context "with a Debian #{container_type} distribution" do
let_it_be(:container, freeze: can_freeze) { create(container_type) } # rubocop:disable Rails/SaveBang
let_it_be(:distribution, freeze: can_freeze) { create("debian_#{container_type}_distribution", container: container) }
let_it_be(:component1, freeze: can_freeze) { create("debian_#{container_type}_component", distribution: distribution, name: 'component1') }
let_it_be(:component2, freeze: can_freeze) { create("debian_#{container_type}_component", distribution: distribution, name: 'component2') }
let_it_be(:architecture0, freeze: true) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'all') }
let_it_be(:architecture1, freeze: can_freeze) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'architecture1') }
let_it_be(:architecture2, freeze: can_freeze) { create("debian_#{container_type}_architecture", distribution: distribution, name: 'architecture2') }
let_it_be(:component_file1, freeze: can_freeze) { create("debian_#{container_type}_component_file", :source, component: component1) }
let_it_be(:component_file2, freeze: can_freeze) { create("debian_#{container_type}_component_file", component: component1, architecture: architecture1) }
let_it_be(:component_file3, freeze: can_freeze) { create("debian_#{container_type}_component_file", :source, component: component2) }
let_it_be(:component_file4, freeze: can_freeze) { create("debian_#{container_type}_component_file", component: component2, architecture: architecture2) }
subject { described_class.new(distribution) }
let(:response) { subject.execute }
context 'with a distribution' do
it_behaves_like 'Destroy Debian Distribution'
end
context 'when destroy fails' do
let(:distribution) { create("debian_#{container_type}_distribution", container: container) }
before do
expect(distribution).to receive(:destroy).and_return(false)
end
it_behaves_like 'Destroy Debian Distribution', "Unable to destroy Debian #{container_type} distribution"
end
end
end
it_behaves_like 'Debian Destroy Distribution Service', :project, true
it_behaves_like 'Debian Destroy Distribution Service', :group, false
end
...@@ -6,6 +6,8 @@ RSpec.describe Packages::Debian::UpdateDistributionService do ...@@ -6,6 +6,8 @@ RSpec.describe Packages::Debian::UpdateDistributionService do
RSpec.shared_examples 'Update Debian Distribution' do |expected_message, expected_components, expected_architectures, component_file_delta = 0| RSpec.shared_examples 'Update Debian Distribution' do |expected_message, expected_components, expected_architectures, component_file_delta = 0|
it 'returns ServiceResponse', :aggregate_failures do it 'returns ServiceResponse', :aggregate_failures do
expect(distribution).to receive(:update).with(simple_params).and_call_original if expected_message.nil? expect(distribution).to receive(:update).with(simple_params).and_call_original if expected_message.nil?
expect(::Packages::Debian::GenerateDistributionWorker).to receive(:perform_async).with(distribution.class.container_type, distribution.id).and_call_original if expected_message.nil?
expect(::Packages::Debian::GenerateDistributionWorker).not_to receive(:perform_async) unless expected_message.nil?
if component_file_delta.zero? if component_file_delta.zero?
expect { response } expect { response }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment