Commit 16775e71 authored by Steve Abrams's avatar Steve Abrams Committed by Andreas Brandl

Conan snapshot and manifest API endpoints

Conan endpoints for returning 'snapshot' and 'manifest'
data to the conan CLI. This follows the v1 conan API.

PackagesConanFileMetadata is created to store metadata for
conan package files.
parent 16020d79
# 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