Commit bde1e878 authored by Andreas Brandl's avatar Andreas Brandl

Merge branch '13345-conan-file-metadatum' into 'master'

Conan snapshot and manifest API endpoints

See merge request gitlab-org/gitlab!16418
parents 16020d79 16775e71
# frozen_string_literal: true
class CreatePackagesConanFileMetadata < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :packages_conan_file_metadata do |t|
t.references :package_file, index: { unique: true }, null: false, foreign_key: { to_table: :packages_package_files, on_delete: :cascade }, type: :bigint
t.timestamps_with_timezone
t.string "recipe_revision", null: false, default: "0", limit: 255
t.string "package_revision", limit: 255
t.string "conan_package_reference", limit: 255
t.integer "conan_file_type", limit: 2, null: false
end
end
end
# frozen_string_literal: true
class CreatePackagesConanMetadata < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :packages_conan_metadata do |t|
t.references :package, index: { unique: true }, null: false, foreign_key: { to_table: :packages_packages, on_delete: :cascade }, type: :bigint
t.timestamps_with_timezone
t.string "package_username", null: false, limit: 255
t.string "package_channel", null: false, limit: 255
end
end
end
......@@ -2653,6 +2653,26 @@ ActiveRecord::Schema.define(version: 2019_10_29_191901) do
t.index ["project_id", "token_encrypted"], name: "index_feature_flags_clients_on_project_id_and_token_encrypted", unique: true
end
create_table "packages_conan_file_metadata", force: :cascade do |t|
t.bigint "package_file_id", null: false
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.string "recipe_revision", limit: 255, default: "0", null: false
t.string "package_revision", limit: 255
t.string "conan_package_reference", limit: 255
t.integer "conan_file_type", limit: 2, null: false
t.index ["package_file_id"], name: "index_packages_conan_file_metadata_on_package_file_id", unique: true
end
create_table "packages_conan_metadata", force: :cascade do |t|
t.bigint "package_id", null: false
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.string "package_username", limit: 255, null: false
t.string "package_channel", limit: 255, null: false
t.index ["package_id"], name: "index_packages_conan_metadata_on_package_id", unique: true
end
create_table "packages_maven_metadata", force: :cascade do |t|
t.bigint "package_id", null: false
t.datetime_with_timezone "created_at", null: false
......@@ -4326,6 +4346,8 @@ ActiveRecord::Schema.define(version: 2019_10_29_191901) do
add_foreign_key "operations_feature_flag_scopes", "operations_feature_flags", column: "feature_flag_id", on_delete: :cascade
add_foreign_key "operations_feature_flags", "projects", on_delete: :cascade
add_foreign_key "operations_feature_flags_clients", "projects", on_delete: :cascade
add_foreign_key "packages_conan_file_metadata", "packages_package_files", column: "package_file_id", on_delete: :cascade
add_foreign_key "packages_conan_metadata", "packages_packages", column: "package_id", on_delete: :cascade
add_foreign_key "packages_maven_metadata", "packages_packages", column: "package_id", name: "fk_be88aed360", on_delete: :cascade
add_foreign_key "packages_package_files", "packages_packages", column: "package_id", name: "fk_86f0f182f8", on_delete: :cascade
add_foreign_key "packages_package_metadata", "packages_packages", column: "package_id", on_delete: :cascade
......
......@@ -2,15 +2,15 @@
module Packages
class ConanPackageFinder
attr_reader :query, :current_user
attr_reader :current_user, :query
def initialize(query, current_user)
@query = query
def initialize(current_user, params)
@current_user = current_user
@query = params[:query]
end
def execute
packages_for_current_user.with_name_like(query).order_name_asc
packages_for_current_user.with_name_like(query).order_name_asc if query
end
private
......
# frozen_string_literal: true
class Packages::ConanFileMetadatum < ApplicationRecord
belongs_to :package_file, inverse_of: :conan_file_metadatum
validates :package_file, presence: true
validates :recipe_revision,
presence: true,
format: { with: Gitlab::Regex.conan_revision_regex }
validates :package_revision, absence: true, if: :recipe_file?
validates :package_revision, format: { with: Gitlab::Regex.conan_revision_regex }, if: :package_file?
validates :conan_package_reference, absence: true, if: :recipe_file?
validates :conan_package_reference, format: { with: Gitlab::Regex.conan_package_reference_regex }, if: :package_file?
enum conan_file_type: { recipe_file: 1, package_file: 2 }
RECIPE_FILES = %w[conanfile.py conanmanifest.txt].freeze
PACKAGE_FILES = %w[conaninfo.txt conanmanifest.txt conan_package.tgz].freeze
end
# frozen_string_literal: true
class Packages::ConanMetadatum < ApplicationRecord
belongs_to :package, inverse_of: :conan_metadatum
validates :package, presence: true
validates :package_username,
presence: true,
format: { with: Gitlab::Regex.conan_recipe_component_regex }
validates :package_channel,
presence: true,
format: { with: Gitlab::Regex.conan_recipe_component_regex }
def recipe
"#{package.name}/#{package.version}@#{package_username}/#{package_channel}"
end
def recipe_path
recipe.tr('@', '/')
end
def self.package_username_from(full_path:)
full_path.tr('/', '+')
end
def self.full_path_from(package_username:)
package_username.tr('+', '/')
end
end
......@@ -5,10 +5,14 @@ class Packages::Package < ApplicationRecord
belongs_to :project
# package_files must be destroyed by ruby code in order to properly remove carrierwave uploads and update project statistics
has_many :package_files, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :conan_metadatum, inverse_of: :package
has_one :maven_metadatum, inverse_of: :package
accepts_nested_attributes_for :conan_metadatum
accepts_nested_attributes_for :maven_metadatum
delegate :recipe, :recipe_path, to: :conan_metadatum, prefix: :conan
validates :project, presence: true
validates :name,
......
......@@ -8,12 +8,17 @@ class Packages::PackageFile < ApplicationRecord
belongs_to :package
has_one :conan_file_metadatum, inverse_of: :package_file
accepts_nested_attributes_for :conan_file_metadatum
validates :package, presence: true
validates :file, presence: true
validates :file_name, presence: true
scope :recent, -> { order(id: :desc) }
scope :with_files_stored_locally, -> { where(file_store: ::Packages::PackageFileUploader::Store::LOCAL) }
scope :with_conan_file_metadata, -> { includes(:conan_file_metadatum) }
mount_uploader :file, Packages::PackageFileUploader
......
# frozen_string_literal: true
class ConanPackagePresenter
include API::Helpers::RelatedResourcesHelpers
include Gitlab::Utils::StrongMemoize
def initialize(recipe, user, project)
@recipe = recipe
@user = user
@project = project
end
def recipe_urls
map_package_files do |package_file|
build_recipe_file_url(package_file) if package_file.conan_file_metadatum.recipe_file?
end
end
def recipe_snapshot
map_package_files do |package_file|
package_file.file_md5 if package_file.conan_file_metadatum.recipe_file?
end
end
def package_urls
map_package_files do |package_file|
build_package_file_url(package_file) if package_file.conan_file_metadatum.package_file?
end
end
def package_snapshot
map_package_files do |package_file|
package_file.file_md5 if package_file.conan_file_metadatum.package_file?
end
end
private
def build_recipe_file_url(package_file)
expose_url(
api_v4_packages_conan_v1_files_export_path(
package_name: package.name,
package_version: package.version,
package_username: package.conan_metadatum.package_username,
package_channel: package.conan_metadatum.package_channel,
recipe_revision: package_file.conan_file_metadatum.recipe_revision,
file_name: package_file.file_name
)
)
end
def build_package_file_url(package_file)
expose_url(
api_v4_packages_conan_v1_files_package_path(
package_name: package.name,
package_version: package.version,
package_username: package.conan_metadatum.package_username,
package_channel: package.conan_metadatum.package_channel,
recipe_revision: package_file.conan_file_metadatum.recipe_revision,
conan_package_reference: package_file.conan_file_metadatum.conan_package_reference,
package_revision: package_file.conan_file_metadatum.package_revision,
file_name: package_file.file_name
)
)
end
def map_package_files
package_files.to_a.map do |package_file|
[package_file.file_name, yield(package_file)]
end.to_h.compact
end
def package_files
return unless package
@package_files ||= package.package_files.with_conan_file_metadata
end
def package
strong_memoize(:package) do
name, version = @recipe.split('@')[0].split('/')
@project.packages.with_name(name).with_version(version).order_created.last
end
end
end
......@@ -23,6 +23,8 @@ module Packages
def search_results
return [] if wildcard_query?
return search_for_single_package(sanitized_query) if params[:query].include?(RECIPE_SEPARATOR)
search_packages(build_query)
end
......@@ -31,11 +33,9 @@ module Packages
end
def build_query
sanitized_query = sanitize_sql_like(params[:query].delete(WILDCARD))
return "#{sanitized_query}%" if params[:query].end_with?(WILDCARD)
return sanitized_query if sanitized_query.include?(RECIPE_SEPARATOR)
"#{sanitized_query}/%"
sanitized_query
end
def feature_available?
......@@ -43,7 +43,21 @@ module Packages
end
def search_packages(query)
Packages::ConanPackageFinder.new(query, current_user).execute.pluck_names
Packages::ConanPackageFinder.new(current_user, query: query).execute.map(&:conan_recipe)
end
def search_for_single_package(query)
name, version, username, _ = query.split(/[@\/]/)
full_path = Packages::ConanMetadatum.full_path_from(package_username: username)
project = Project.find_by_full_path(full_path)
return unless current_user.can?(:read_package, project)
result = project.packages.with_name(name).with_version(version).order_created.last
[result&.conan_recipe].compact
end
def sanitized_query
@sanitized_query ||= sanitize_sql_like(params[:query].delete(WILDCARD))
end
end
end
......
This diff is collapsed.
......@@ -808,6 +808,28 @@ module EE
end
end
module ConanPackage
class ConanPackageManifest < Grape::Entity
expose :package_urls, merge: true
end
class ConanPackageSnapshot < Grape::Entity
expose :package_snapshot, merge: true
end
class ConanRecipeManifest < Grape::Entity
expose :recipe_urls, merge: true
end
class ConanRecipeSnapshot < Grape::Entity
expose :recipe_snapshot, merge: true
end
class ConanUploadUrls < Grape::Entity
expose :upload_urls, merge: true
end
end
class NpmPackage < Grape::Entity
expose :name
expose :versions
......
......@@ -6,6 +6,23 @@ module EE
extend ActiveSupport::Concern
class_methods do
def conan_file_name_regex
@conan_file_name_regex ||=
%r{\A#{(::Packages::ConanFileMetadatum::RECIPE_FILES + ::Packages::ConanFileMetadatum::PACKAGE_FILES).join("|")}\z}.freeze
end
def conan_package_reference_regex
@conan_package_reference_regex ||= %r{\A[A-Za-z0-9]+\z}.freeze
end
def conan_revision_regex
@conan_revision_regex ||= %r{\A0\z}.freeze
end
def conan_recipe_component_regex
@conan_recipe_component_regex ||= %r{\A(\w[.+-]?)+\z}.freeze
end
def package_name_regex
@package_name_regex ||= %r{\A\@?(([\w\-\.\+]*)\/)*([\w\-\.]+)@?(([\w\-\.\+]*)\/)*([\w\-\.]*)\z}.freeze
end
......
......@@ -31,15 +31,98 @@ FactoryBot.define do
end
factory :conan_package do
sequence(:name) { |n| "package-#{n}/1.0.0@#{project.full_path.tr('/', '+')}/stable"}
conan_metadatum
after :build do |package|
package.conan_metadatum.package_username = Packages::ConanMetadatum.package_username_from(
full_path: package.project.full_path
)
end
sequence(:name) { |n| "package-#{n}" }
version { '1.0.0' }
package_type { 'conan' }
after :create do |package|
create :conan_package_file, :conan_recipe_file, package: package
create :conan_package_file, :conan_recipe_manifest, package: package
create :conan_package_file, :conan_package_info, package: package
create :conan_package_file, :conan_package_manifest, package: package
create :conan_package_file, :conan_package, package: package
end
end
end
factory :package_file, class: Packages::PackageFile do
package
factory :conan_package_file do
trait(:conan_recipe_file) do
after :create do |package_file|
create :conan_file_metadatum, :recipe_file, package_file: package_file
end
file { fixture_file_upload('ee/spec/fixtures/conan/recipe_conanfile.py') }
file_name { 'recipe_conanfile.py' }
file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
file_md5 { '12345abcde' }
file_type { 'py' }
size { 400.kilobytes }
end
trait(:conan_recipe_manifest) do
after :create do |package_file|
create :conan_file_metadatum, :recipe_file, package_file: package_file
end
file { fixture_file_upload('ee/spec/fixtures/conan/recipe_conanmanifest.txt') }
file_name { 'recipe_conanmanifest.txt' }
file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
file_md5 { '12345abcde' }
file_type { 'txt' }
size { 400.kilobytes }
end
trait(:conan_package_manifest) do
after :create do |package_file|
create :conan_file_metadatum, :package_file, package_file: package_file
end
file { fixture_file_upload('ee/spec/fixtures/conan/package_conanmanifest.txt') }
file_name { 'package_conanmanifest.txt' }
file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
file_md5 { '12345abcde' }
file_type { 'txt' }
size { 400.kilobytes }
end
trait(:conan_package_info) do
after :create do |package_file|
create :conan_file_metadatum, :package_file, package_file: package_file
end
file { fixture_file_upload('ee/spec/fixtures/conan/package_conaninfo.txt') }
file_name { 'package_conaninfo.txt' }
file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
file_md5 { '12345abcde' }
file_type { 'txt' }
size { 400.kilobytes }
end
trait(:conan_package) do
after :create do |package_file|
create :conan_file_metadatum, :package_file, package_file: package_file
end
file { fixture_file_upload('ee/spec/fixtures/conan/conan_package.tgz') }
file_name { 'conan_package.tgz' }
file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
file_md5 { '12345abcde' }
file_type { 'tgz' }
size { 400.kilobytes }
end
end
trait(:jar) do
file { fixture_file_upload('ee/spec/fixtures/maven/my-app-1.0-20180724.124855-1.jar') }
file_name { 'my-app-1.0-20180724.124855-1.jar' }
......@@ -84,4 +167,25 @@ FactoryBot.define do
app_name { 'my-app' }
app_version { '1.0-SNAPSHOT' }
end
factory :conan_metadatum, class: Packages::ConanMetadatum do
package
package_username { 'username' }
package_channel { 'stable' }
end
factory :conan_file_metadatum, class: Packages::ConanFileMetadatum do
package_file
recipe_revision { '0' }
trait(:recipe_file) do
conan_file_type { 'recipe_file' }
end
trait(:package_file) do
conan_file_type { 'package_file' }
package_revision { '0' }
conan_package_reference { '123456789' }
end
end
end
......@@ -2,13 +2,14 @@
require 'spec_helper'
describe Packages::ConanPackageFinder do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
describe '#execute' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public) }
let!(:conan_package) { create(:conan_package, project: project) }
let!(:conan_package2) { create(:conan_package, project: project) }
subject { described_class.new(query, user).execute }
subject { described_class.new(user, query: query).execute }
context 'packages that are not visible to user' do
let!(:non_visible_project) { create(:project, :private) }
......
[settings]
arch=x86_64
build_type=Release
compiler=apple-clang
compiler.libcxx=libc++
compiler.version=10.0
os=Macos
[requires]
[options]
shared=False
[full_settings]
arch=x86_64
build_type=Release
compiler=apple-clang
compiler.libcxx=libc++
compiler.version=10.0
os=Macos
[full_requires]
[full_options]
shared=False
[recipe_hash]
b4b91125b36b40a7076a98310588f820
[env]
1565723794
conaninfo.txt: 2774ebe649804c1cd9430f26ab0ead14
include/hello.h: 8727846905bd09baecf8bdc1edb1f46e
lib/libhello.a: 7f2aaa8b6f3bc316bba59e47b6a0bd43
from conans import ConanFile, CMake, tools
class HelloConan(ConanFile):
name = "Hello"
version = "0.1"
license = "<Put the package license here>"
author = "<Put your name here> <And your email here>"
url = "<Package recipe repository url here, for issues about the package>"
description = "<Description of Hello here>"
topics = ("<Put some tag here>", "<here>", "<and here>")
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False]}
default_options = "shared=False"
generators = "cmake"
def source(self):
self.run("git clone https://github.com/conan-io/hello.git")
# This small hack might be useful to guarantee proper /MT /MD linkage
# in MSVC if the packaged project doesn't have variables to set it
# properly
tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(HelloWorld)",
'''PROJECT(HelloWorld)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()''')
def build(self):
cmake = CMake(self)
cmake.configure(source_folder="hello")
cmake.build()
# Explicit way:
# self.run('cmake %s/hello %s'
# % (self.source_folder, cmake.command_line))
# self.run("cmake --build . %s" % cmake.build_config)
def package(self):
self.copy("*.h", dst="include", src="hello")
self.copy("*hello.lib", dst="lib", keep_path=False)
self.copy("*.dll", dst="bin", keep_path=False)
self.copy("*.so", dst="lib", keep_path=False)
self.copy("*.dylib", dst="lib", keep_path=False)
self.copy("*.a", dst="lib", keep_path=False)
def package_info(self):
self.cpp_info.libs = ["hello"]
1565723790
conanfile.py: 7c042b95312cc4c4ee89199dc51aebf9
......@@ -3,6 +3,45 @@
require 'spec_helper'
describe Gitlab::Regex do
describe '.conan_file_name_regex' do
subject { described_class.conan_file_name_regex }
it { is_expected.to match('conanfile.py') }
it { is_expected.to match('conan_package.tgz') }
it { is_expected.not_to match('foo.txt') }
it { is_expected.not_to match('!!()()') }
end
describe '.conan_package_reference_regex' do
subject { described_class.conan_package_reference_regex }
it { is_expected.to match('123456789') }
it { is_expected.to match('asdf1234') }
it { is_expected.not_to match('@foo') }
it { is_expected.not_to match('0/pack+age/1@1/0') }
it { is_expected.not_to match('!!()()') }
end
describe '.conan_revision_regex' do
subject { described_class.conan_revision_regex }
it { is_expected.to match('0') }
it { is_expected.not_to match('foo') }
it { is_expected.not_to match('!!()()') }
end
describe '.conan_recipe_component_regex' do
subject { described_class.conan_recipe_component_regex }
it { is_expected.to match('foobar') }
it { is_expected.to match('foo_bar') }
it { is_expected.to match('foo+bar') }
it { is_expected.to match('1.0.0') }
it { is_expected.not_to match('foo@bar') }
it { is_expected.not_to match('foo/bar') }
it { is_expected.not_to match('!!()()') }
end
describe '.feature_flag_regex' do
subject { described_class.feature_flag_regex }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::ConanFileMetadatum, type: :model do
describe 'relationships' do
it { is_expected.to belong_to(:package_file) }
end
describe 'validations' do
let(:package_file) do
create(:package_file,
file: fixture_file_upload('ee/spec/fixtures/conan/recipe_conanfile.py'),
file_name: 'recipe_conanfile.py')
end
it { is_expected.to validate_presence_of(:package_file) }
it { is_expected.to validate_presence_of(:recipe_revision) }
describe '#recipe_revision' do
it { is_expected.to allow_value("0").for(:recipe_revision) }
it { is_expected.not_to allow_value(nil).for(:recipe_revision) }
end
describe '#package_revision_for_package_file' do
context 'recipe file' do
let(:conan_file_metadatum) { build(:conan_file_metadatum, :recipe_file, package_file: package_file) }
it 'is valid with empty value' do
conan_file_metadatum.package_revision = nil
expect(conan_file_metadatum).to be_valid
end
it 'is invalid with value' do
conan_file_metadatum.package_revision = '0'
expect(conan_file_metadatum).to be_invalid
end
end
context 'package file' do
let(:conan_file_metadatum) { build(:conan_file_metadatum, :package_file, package_file: package_file) }
it 'is valid with default value' do
conan_file_metadatum.package_revision = '0'
expect(conan_file_metadatum).to be_valid
end
it 'is invalid with non-default value' do
conan_file_metadatum.package_revision = 'foo'
expect(conan_file_metadatum).to be_invalid
end
end
end
describe '#conan_package_reference_for_package_file' do
context 'recipe file' do
let(:conan_file_metadatum) { build(:conan_file_metadatum, :recipe_file, package_file: package_file) }
it 'is valid with empty value' do
conan_file_metadatum.conan_package_reference = nil
expect(conan_file_metadatum).to be_valid
end
it 'is invalid with value' do
conan_file_metadatum.conan_package_reference = '123456789'
expect(conan_file_metadatum).to be_invalid
end
end
context 'package file' do
let(:conan_file_metadatum) { build(:conan_file_metadatum, :package_file, package_file: package_file) }
it 'is valid with acceptable value' do
conan_file_metadatum.conan_package_reference = '123456asdf'
expect(conan_file_metadatum).to be_valid
end
it 'is invalid with invalid value' do
conan_file_metadatum.conan_package_reference = 'foo@bar'
expect(conan_file_metadatum).to be_invalid
end
it 'is invalid when nil' do
conan_file_metadatum.conan_package_reference = nil
expect(conan_file_metadatum).to be_invalid
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::ConanMetadatum, type: :model do
describe 'relationships' do
it { is_expected.to belong_to(:package) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:package) }
it { is_expected.to validate_presence_of(:package_username) }
it { is_expected.to validate_presence_of(:package_channel) }
describe '#package_username' do
it { is_expected.to allow_value("my-package+username").for(:package_username) }
it { is_expected.not_to allow_value("my/package").for(:package_username) }
it { is_expected.not_to allow_value("my(package)").for(:package_username) }
it { is_expected.not_to allow_value("my@package").for(:package_username) }
end
describe '#package_channel' do
it { is_expected.to allow_value("beta").for(:package_channel) }
it { is_expected.to allow_value("stable+1.0").for(:package_channel) }
it { is_expected.not_to allow_value("my/channel").for(:package_channel) }
it { is_expected.not_to allow_value("my(channel)").for(:package_channel) }
it { is_expected.not_to allow_value("my@channel").for(:package_channel) }
end
end
describe '#recipe' do
let(:package) { create(:conan_package) }
it 'returns the recipe' do
expect(package.conan_recipe).to eq("#{package.name}/#{package.version}@#{package.conan_metadatum.package_username}/#{package.conan_metadatum.package_channel}")
end
end
describe '#recipe_url' do
let(:package) { create(:conan_package) }
it 'returns the recipe url' do
expect(package.conan_recipe_path).to eq("#{package.name}/#{package.version}/#{package.conan_metadatum.package_username}/#{package.conan_metadatum.package_channel}")
end
end
describe '.package_username_from' do
let(:full_path) { 'foo/bar/baz-buz' }
it 'returns the username formatted package path' do
expect(described_class.package_username_from(full_path: full_path)).to eq('foo+bar+baz-buz')
end
end
describe '.full_path_from' do
let(:username) { 'foo+bar+baz-buz' }
it 'returns the username formatted package path' do
expect(described_class.full_path_from(package_username: username)).to eq('foo/bar/baz-buz')
end
end
end
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Packages::PackageFile, type: :model do
describe 'relationships' do
it { is_expected.to belong_to(:package) }
it { is_expected.to have_one(:conan_file_metadatum) }
end
describe 'validations' do
......
# frozen_string_literal: true
require 'spec_helper'
describe ConanPackagePresenter do
let(:user) { create(:user) }
let(:project) { create(:project) }
describe '#recipe_urls' do
subject { described_class.new(recipe, user, project).recipe_urls }
context 'no existing package' do
let(:recipe) { "my-pkg/v1.0.0/#{project.full_path}/stable" }
it { is_expected.to be_empty }
end
context 'existing package' do
let(:package) { create(:conan_package, project: project) }
let(:recipe) { package.conan_recipe }
let(:expected_result) do
{
"recipe_conanfile.py" => "#{Settings.build_base_gitlab_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/recipe_conanfile.py",
"recipe_conanmanifest.txt" => "#{Settings.build_base_gitlab_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/export/recipe_conanmanifest.txt"
}
end
it { is_expected.to eq(expected_result) }
end
end
describe '#recipe_snapshot' do
subject { described_class.new(recipe, user, project).recipe_snapshot }
context 'no existing package' do
let(:recipe) { "my-pkg/v1.0.0/#{project.full_path}/stable" }
it { is_expected.to be_empty }
end
context 'existing package' do
let(:package) { create(:conan_package, project: project) }
let(:recipe) { package.conan_recipe }
let(:expected_result) do
{
"recipe_conanfile.py" => '12345abcde',
"recipe_conanmanifest.txt" => '12345abcde'
}
end
it { is_expected.to eq(expected_result) }
end
end
describe '#package_urls' do
subject { described_class.new(recipe, user, project).package_urls }
context 'no existing package' do
let(:recipe) { "my-pkg/v1.0.0/#{project.full_path}/stable" }
it { is_expected.to be_empty }
end
context 'existing package' do
let(:package) { create(:conan_package, project: project) }
let(:recipe) { package.conan_recipe }
let(:expected_result) do
{
"package_conaninfo.txt" => "#{Settings.build_base_gitlab_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/package_conaninfo.txt",
"package_conanmanifest.txt" => "#{Settings.build_base_gitlab_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/package_conanmanifest.txt",
"conan_package.tgz" => "#{Settings.build_base_gitlab_url}/api/v4/packages/conan/v1/files/#{package.conan_recipe_path}/0/package/123456789/0/conan_package.tgz"
}
end
it { is_expected.to eq(expected_result) }
end
end
describe '#package_snapshot' do
subject { described_class.new(recipe, user, project).package_snapshot }
context 'no existing package' do
let(:recipe) { "my-pkg/v1.0.0/#{project.full_path}/stable" }
it { is_expected.to be_empty }
end
context 'existing package' do
let(:package) { create(:conan_package, project: project) }
let(:recipe) { package.conan_recipe }
let(:expected_result) do
{
"package_conaninfo.txt" => '12345abcde',
"package_conanmanifest.txt" => '12345abcde',
"conan_package.tgz" => '12345abcde'
}
end
it { is_expected.to eq(expected_result) }
end
end
end
This diff is collapsed.
......@@ -10,6 +10,10 @@ describe Packages::Conan::SearchService do
subject { described_class.new(user, query: query) }
before do
project.add_developer(user)
end
describe '#execute' do
context 'feature unavailable' do
let(:query) { '' }
......@@ -34,7 +38,7 @@ describe Packages::Conan::SearchService do
result = subject.execute
expect(result.status).to eq :success
expect(result.payload).to eq(results: [conan_package.name, conan_package2.name])
expect(result.payload).to eq(results: [conan_package.conan_recipe, conan_package2.conan_recipe])
end
end
......@@ -50,24 +54,24 @@ describe Packages::Conan::SearchService do
end
context 'with no wildcard' do
let(:query) { conan_package.name.split('/').first }
let(:query) { conan_package.name }
it 'makes a search using the beginning of the recipe' do
result = subject.execute
expect(result.status).to eq :success
expect(result.payload).to eq(results: [conan_package.name])
expect(result.payload).to eq(results: [conan_package.conan_recipe])
end
end
context 'with full recipe match' do
let(:query) { conan_package.name }
let(:query) { conan_package.conan_recipe }
it 'makes an exact search' do
result = subject.execute
expect(result.status).to eq :success
expect(result.payload).to eq(results: [conan_package.name])
expect(result.payload).to eq(results: [conan_package.conan_recipe])
end
end
......
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