Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
71a89b9e
Commit
71a89b9e
authored
Mar 26, 2021
by
Steve Abrams
Committed by
David Fernandez
Mar 26, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Gem metadata extraction
Takes a gem file and extracts the metadata
parent
55959477
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
741 additions
and
16 deletions
+741
-16
app/assets/javascripts/packages/list/constants.js
app/assets/javascripts/packages/list/constants.js
+4
-0
app/assets/javascripts/packages/shared/constants.js
app/assets/javascripts/packages/shared/constants.js
+1
-0
app/assets/javascripts/packages/shared/utils.js
app/assets/javascripts/packages/shared/utils.js
+2
-0
app/services/packages/rubygems/create_dependencies_service.rb
...services/packages/rubygems/create_dependencies_service.rb
+44
-0
app/services/packages/rubygems/create_gemspec_service.rb
app/services/packages/rubygems/create_gemspec_service.rb
+42
-0
app/services/packages/rubygems/metadata_extraction_service.rb
...services/packages/rubygems/metadata_extraction_service.rb
+56
-0
app/services/packages/rubygems/process_gem_service.rb
app/services/packages/rubygems/process_gem_service.rb
+124
-0
app/workers/all_queues.yml
app/workers/all_queues.yml
+8
-0
app/workers/packages/rubygems/extraction_worker.rb
app/workers/packages/rubygems/extraction_worker.rb
+27
-0
changelogs/unreleased/301175-gemfile-extraction-service.yml
changelogs/unreleased/301175-gemfile-extraction-service.yml
+5
-0
db/migrate/20210223230600_update_rubygems_metadata_metadata.rb
...grate/20210223230600_update_rubygems_metadata_metadata.rb
+19
-0
db/schema_migrations/20210223230600
db/schema_migrations/20210223230600
+1
-0
db/structure.sql
db/structure.sql
+1
-1
lib/api/rubygem_packages.rb
lib/api/rubygem_packages.rb
+10
-2
locale/gitlab.pot
locale/gitlab.pot
+6
-0
spec/factories/packages.rb
spec/factories/packages.rb
+2
-2
spec/factories/packages/package_file.rb
spec/factories/packages/package_file.rb
+8
-0
spec/fixtures/api/schemas/graphql/packages/package_details.json
...ixtures/api/schemas/graphql/packages/package_details.json
+1
-1
spec/fixtures/packages/rubygems/package-0.0.1.gem
spec/fixtures/packages/rubygems/package-0.0.1.gem
+0
-0
spec/fixtures/packages/rubygems/package.gem
spec/fixtures/packages/rubygems/package.gem
+0
-0
spec/fixtures/packages/rubygems/package.gemspec
spec/fixtures/packages/rubygems/package.gemspec
+37
-10
spec/frontend/packages/details/store/getters_spec.js
spec/frontend/packages/details/store/getters_spec.js
+2
-0
spec/frontend/packages/mock_data.js
spec/frontend/packages/mock_data.js
+17
-0
spec/frontend/packages/shared/utils_spec.js
spec/frontend/packages/shared/utils_spec.js
+1
-0
spec/services/packages/rubygems/create_dependencies_service_spec.rb
...ces/packages/rubygems/create_dependencies_service_spec.rb
+33
-0
spec/services/packages/rubygems/create_gemspec_service_spec.rb
...services/packages/rubygems/create_gemspec_service_spec.rb
+28
-0
spec/services/packages/rubygems/metadata_extraction_service_spec.rb
...ces/packages/rubygems/metadata_extraction_service_spec.rb
+50
-0
spec/services/packages/rubygems/process_gem_service_spec.rb
spec/services/packages/rubygems/process_gem_service_spec.rb
+134
-0
spec/support/helpers/rubygems_helpers.rb
spec/support/helpers/rubygems_helpers.rb
+11
-0
spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb
...xamples/requests/api/rubygems_packages_shared_examples.rb
+13
-0
spec/workers/packages/rubygems/extraction_worker_spec.rb
spec/workers/packages/rubygems/extraction_worker_spec.rb
+54
-0
No files found.
app/assets/javascripts/packages/list/constants.js
View file @
71a89b9e
...
@@ -82,6 +82,10 @@ export const PACKAGE_TYPES = [
...
@@ -82,6 +82,10 @@ export const PACKAGE_TYPES = [
title
:
s__
(
'
PackageRegistry|PyPI
'
),
title
:
s__
(
'
PackageRegistry|PyPI
'
),
type
:
PackageType
.
PYPI
,
type
:
PackageType
.
PYPI
,
},
},
{
title
:
s__
(
'
PackageRegistry|RubyGems
'
),
type
:
PackageType
.
RUBYGEMS
,
},
];
];
export
const
LIST_TITLE_TEXT
=
s__
(
'
PackageRegistry|Package Registry
'
);
export
const
LIST_TITLE_TEXT
=
s__
(
'
PackageRegistry|Package Registry
'
);
...
...
app/assets/javascripts/packages/shared/constants.js
View file @
71a89b9e
...
@@ -7,6 +7,7 @@ export const PackageType = {
...
@@ -7,6 +7,7 @@ export const PackageType = {
NUGET
:
'
nuget
'
,
NUGET
:
'
nuget
'
,
PYPI
:
'
pypi
'
,
PYPI
:
'
pypi
'
,
COMPOSER
:
'
composer
'
,
COMPOSER
:
'
composer
'
,
RUBYGEMS
:
'
rubygems
'
,
GENERIC
:
'
generic
'
,
GENERIC
:
'
generic
'
,
};
};
...
...
app/assets/javascripts/packages/shared/utils.js
View file @
71a89b9e
...
@@ -19,6 +19,8 @@ export const getPackageTypeLabel = (packageType) => {
...
@@ -19,6 +19,8 @@ export const getPackageTypeLabel = (packageType) => {
return
s__
(
'
PackageType|NuGet
'
);
return
s__
(
'
PackageType|NuGet
'
);
case
PackageType
.
PYPI
:
case
PackageType
.
PYPI
:
return
s__
(
'
PackageType|PyPI
'
);
return
s__
(
'
PackageType|PyPI
'
);
case
PackageType
.
RUBYGEMS
:
return
s__
(
'
PackageType|RubyGems
'
);
case
PackageType
.
COMPOSER
:
case
PackageType
.
COMPOSER
:
return
s__
(
'
PackageType|Composer
'
);
return
s__
(
'
PackageType|Composer
'
);
case
PackageType
.
GENERIC
:
case
PackageType
.
GENERIC
:
...
...
app/services/packages/rubygems/create_dependencies_service.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
module
Packages
module
Rubygems
class
CreateDependenciesService
include
BulkInsertSafe
def
initialize
(
package
,
gemspec
)
@package
=
package
@gemspec
=
gemspec
end
def
execute
set_dependencies
end
private
attr_reader
:package
,
:gemspec
def
set_dependencies
Packages
::
Dependency
.
transaction
do
dependency_type_rows
=
gemspec
.
dependencies
.
map
do
|
dependency
|
dependency
=
Packages
::
Dependency
.
safe_find_or_create_by!
(
name:
dependency
.
name
,
version_pattern:
dependency
.
requirement
.
to_s
)
{
dependency_id:
dependency
.
id
,
package_id:
package
.
id
,
dependency_type: :dependencies
}
end
package
.
dependency_links
.
upsert_all
(
dependency_type_rows
,
unique_by:
%i[package_id dependency_id dependency_type]
)
end
end
end
end
end
app/services/packages/rubygems/create_gemspec_service.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
module
Packages
module
Rubygems
class
CreateGemspecService
def
initialize
(
package
,
gemspec
)
@package
=
package
@gemspec
=
gemspec
end
def
execute
write_gemspec_to_file
end
private
attr_reader
:package
,
:gemspec
def
write_gemspec_to_file
file
=
Tempfile
.
new
begin
content
=
gemspec
.
to_ruby
file
.
write
(
content
)
file
.
flush
package
.
package_files
.
create!
(
file:
file
,
size:
file
.
size
,
file_name:
"
#{
gemspec
.
name
}
.gemspec"
,
file_sha1:
Digest
::
SHA1
.
hexdigest
(
content
),
file_md5:
Digest
::
MD5
.
hexdigest
(
content
),
file_sha256:
Digest
::
SHA256
.
hexdigest
(
content
)
)
ensure
file
.
close
file
.
unlink
end
end
end
end
end
app/services/packages/rubygems/metadata_extraction_service.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
module
Packages
module
Rubygems
class
MetadataExtractionService
def
initialize
(
package
,
gemspec
)
@package
=
package
@gemspec
=
gemspec
end
def
execute
write_metadata
end
private
attr_reader
:package
,
:gemspec
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/PerceivedComplexity
# rubocop:disable Metrics/CyclomaticComplexity
def
write_metadata
metadatum
.
update!
(
authors:
gemspec
&
.
authors
,
files:
gemspec
&
.
files
&
.
to_json
,
summary:
gemspec
&
.
summary
,
description:
gemspec
&
.
description
,
email:
gemspec
&
.
email
,
homepage:
gemspec
&
.
homepage
,
licenses:
gemspec
&
.
licenses
&
.
to_json
,
metadata:
gemspec
&
.
metadata
&
.
to_json
,
author:
gemspec
&
.
author
,
bindir:
gemspec
&
.
bindir
,
executables:
gemspec
&
.
executables
&
.
to_json
,
extensions:
gemspec
&
.
extensions
&
.
to_json
,
extra_rdoc_files:
gemspec
&
.
extra_rdoc_files
&
.
to_json
,
platform:
gemspec
&
.
platform
,
post_install_message:
gemspec
&
.
post_install_message
,
rdoc_options:
gemspec
&
.
rdoc_options
&
.
to_json
,
require_paths:
gemspec
&
.
require_paths
&
.
to_json
,
required_ruby_version:
gemspec
&
.
required_ruby_version
&
.
to_s
,
required_rubygems_version:
gemspec
&
.
required_rubygems_version
&
.
to_s
,
requirements:
gemspec
&
.
requirements
&
.
to_json
,
rubygems_version:
gemspec
&
.
rubygems_version
)
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/CyclomaticComplexity
def
metadatum
Packages
::
Rubygems
::
Metadatum
.
safe_find_or_create_by!
(
package:
package
)
end
end
end
end
app/services/packages/rubygems/process_gem_service.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
require
'rubygems/package'
module
Packages
module
Rubygems
class
ProcessGemService
include
Gitlab
::
Utils
::
StrongMemoize
include
ExclusiveLeaseGuard
ExtractionError
=
Class
.
new
(
StandardError
)
DEFAULT_LEASE_TIMEOUT
=
1
.
hour
.
to_i
.
freeze
def
initialize
(
package_file
)
@package_file
=
package_file
end
def
execute
return
success
if
process_gem
error
(
'Gem was not processed'
)
end
private
attr_reader
:package_file
def
process_gem
return
false
unless
package_file
try_obtain_lease
do
package
.
transaction
do
rename_package_and_set_version
rename_package_file
::
Packages
::
Rubygems
::
MetadataExtractionService
.
new
(
package
,
gemspec
).
execute
::
Packages
::
Rubygems
::
CreateGemspecService
.
new
(
package
,
gemspec
).
execute
::
Packages
::
Rubygems
::
CreateDependenciesService
.
new
(
package
,
gemspec
).
execute
cleanup_temp_package
end
end
true
end
def
rename_package_and_set_version
package
.
update!
(
name:
gemspec
.
name
,
version:
gemspec
.
version
,
status: :default
)
end
def
rename_package_file
# Updating file_name updates the path where the file is stored.
# We must pass the file again so that CarrierWave can handle the update
package_file
.
update!
(
file_name:
"
#{
gemspec
.
name
}
-
#{
gemspec
.
version
}
.gem"
,
file:
package_file
.
file
,
package_id:
package
.
id
)
end
def
cleanup_temp_package
temp_package
.
destroy
if
package
.
id
!=
temp_package
.
id
end
def
gemspec
strong_memoize
(
:gemspec
)
do
gem
.
spec
end
end
def
success
ServiceResponse
.
success
(
payload:
{
package:
package
})
end
def
error
(
message
)
ServiceResponse
.
error
(
message:
message
)
end
def
temp_package
strong_memoize
(
:temp_package
)
do
package_file
.
package
end
end
def
package
strong_memoize
(
:package
)
do
# if package with name/version already exists, use that package
package
=
temp_package
.
project
.
packages
.
rubygems
.
with_name
(
gemspec
.
name
)
.
with_version
(
gemspec
.
version
.
to_s
)
.
last
package
||
temp_package
end
end
def
gem
# use_file will set an exclusive lease on the file for as long as
# the resulting gem object is being used. This means we are not
# able to rename the package_file while also using the gem object.
# We need to use a separate AR object to create the gem file to allow
# `package_file` to be free for update so we re-find the file here.
Packages
::
PackageFile
.
find
(
package_file
.
id
).
file
.
use_file
do
|
file_path
|
Gem
::
Package
.
new
(
File
.
open
(
file_path
))
end
rescue
raise
ExtractionError
.
new
(
'Unable to read gem file'
)
end
# used by ExclusiveLeaseGuard
def
lease_key
"packages:rubygems:process_gem_service:package:
#{
package
.
id
}
"
end
# used by ExclusiveLeaseGuard
def
lease_timeout
DEFAULT_LEASE_TIMEOUT
end
end
end
end
app/workers/all_queues.yml
View file @
71a89b9e
...
@@ -1107,6 +1107,14 @@
...
@@ -1107,6 +1107,14 @@
:weight:
1
:weight:
1
:idempotent:
:idempotent:
:tags: []
:tags: []
-
:name: package_repositories:packages_rubygems_extraction
:feature_category: :package_registry
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight:
1
:idempotent:
true
:tags: []
-
:name: pipeline_background:archive_trace
-
:name: pipeline_background:archive_trace
:feature_category: :continuous_integration
:feature_category: :continuous_integration
:has_external_dependencies:
:has_external_dependencies:
...
...
app/workers/packages/rubygems/extraction_worker.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
module
Packages
module
Rubygems
class
ExtractionWorker
# rubocop:disable Scalability/IdempotentWorker
include
ApplicationWorker
queue_namespace
:package_repositories
feature_category
:package_registry
deduplicate
:until_executing
idempotent!
def
perform
(
package_file_id
)
package_file
=
::
Packages
::
PackageFile
.
find_by_id
(
package_file_id
)
return
unless
package_file
::
Packages
::
Rubygems
::
ProcessGemService
.
new
(
package_file
).
execute
rescue
::
Packages
::
Rubygems
::
ProcessGemService
::
ExtractionError
=>
e
Gitlab
::
ErrorTracking
.
log_exception
(
e
,
project_id:
package_file
.
project_id
)
package_file
.
package
.
destroy!
end
end
end
end
changelogs/unreleased/301175-gemfile-extraction-service.yml
0 → 100644
View file @
71a89b9e
---
title
:
Update RubyGems metadata constraints and add gem metadata extraction
merge_request
:
53673
author
:
type
:
changed
db/migrate/20210223230600_update_rubygems_metadata_metadata.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
class
UpdateRubygemsMetadataMetadata
<
ActiveRecord
::
Migration
[
6.0
]
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
up
remove_text_limit
:packages_rubygems_metadata
,
:metadata
add_text_limit
:packages_rubygems_metadata
,
:metadata
,
30000
end
def
down
remove_text_limit
:packages_rubygems_metadata
,
:metadata
add_text_limit
:packages_rubygems_metadata
,
:metadata
,
255
,
validate:
false
end
end
db/schema_migrations/20210223230600
0 → 100644
View file @
71a89b9e
18d64af208338baec9d56a6ac9d7fc35aaeb79d3f8036d3cf5bcc72879827299
\ No newline at end of file
db/structure.sql
View file @
71a89b9e
...
@@ -15658,7 +15658,7 @@ CREATE TABLE packages_rubygems_metadata (
...
@@ -15658,7 +15658,7 @@ CREATE TABLE packages_rubygems_metadata (
CONSTRAINT check_b7b296b420 CHECK ((char_length(author) <= 255)),
CONSTRAINT check_b7b296b420 CHECK ((char_length(author) <= 255)),
CONSTRAINT check_bf16b21a47 CHECK ((char_length(rdoc_options) <= 255)),
CONSTRAINT check_bf16b21a47 CHECK ((char_length(rdoc_options) <= 255)),
CONSTRAINT check_ca641a3354 CHECK ((char_length(required_ruby_version) <= 255)),
CONSTRAINT check_ca641a3354 CHECK ((char_length(required_ruby_version) <= 255)),
CONSTRAINT check_ea02f4800f CHECK ((char_length(metadata) <=
255
)),
CONSTRAINT check_ea02f4800f CHECK ((char_length(metadata) <=
30000
)),
CONSTRAINT check_f76bad1a9a CHECK ((char_length(require_paths) <= 255))
CONSTRAINT check_f76bad1a9a CHECK ((char_length(require_paths) <= 255))
);
);
lib/api/rubygem_packages.rb
View file @
71a89b9e
...
@@ -99,6 +99,8 @@ module API
...
@@ -99,6 +99,8 @@ module API
track_package_event
(
'push_package'
,
:rubygems
)
track_package_event
(
'push_package'
,
:rubygems
)
package_file
=
nil
ActiveRecord
::
Base
.
transaction
do
ActiveRecord
::
Base
.
transaction
do
package
=
::
Packages
::
CreateTemporaryPackageService
.
new
(
package
=
::
Packages
::
CreateTemporaryPackageService
.
new
(
user_project
,
current_user
,
declared_params
.
merge
(
build:
current_authenticated_job
)
user_project
,
current_user
,
declared_params
.
merge
(
build:
current_authenticated_job
)
...
@@ -109,12 +111,18 @@ module API
...
@@ -109,12 +111,18 @@ module API
file_name:
PACKAGE_FILENAME
file_name:
PACKAGE_FILENAME
}
}
::
Packages
::
CreatePackageFileService
.
new
(
package_file
=
::
Packages
::
CreatePackageFileService
.
new
(
package
,
file_params
.
merge
(
build:
current_authenticated_job
)
package
,
file_params
.
merge
(
build:
current_authenticated_job
)
).
execute
).
execute
end
end
created!
if
package_file
::
Packages
::
Rubygems
::
ExtractionWorker
.
perform_async
(
package_file
.
id
)
# rubocop:disable CodeReuse/Worker
created!
else
bad_request!
(
'Package creation failed'
)
end
rescue
ObjectStorage
::
RemoteStoreError
=>
e
rescue
ObjectStorage
::
RemoteStoreError
=>
e
Gitlab
::
ErrorTracking
.
track_exception
(
e
,
extra:
{
file_name:
params
[
:file_name
],
project_id:
user_project
.
id
})
Gitlab
::
ErrorTracking
.
track_exception
(
e
,
extra:
{
file_name:
params
[
:file_name
],
project_id:
user_project
.
id
})
...
...
locale/gitlab.pot
View file @
71a89b9e
...
@@ -22051,6 +22051,9 @@ msgstr ""
...
@@ -22051,6 +22051,9 @@ msgstr ""
msgid "PackageRegistry|Remove package"
msgid "PackageRegistry|Remove package"
msgstr ""
msgstr ""
msgid "PackageRegistry|RubyGems"
msgstr ""
msgid "PackageRegistry|Settings for Maven packages"
msgid "PackageRegistry|Settings for Maven packages"
msgstr ""
msgstr ""
...
@@ -22147,6 +22150,9 @@ msgstr ""
...
@@ -22147,6 +22150,9 @@ msgstr ""
msgid "PackageType|PyPI"
msgid "PackageType|PyPI"
msgstr ""
msgstr ""
msgid "PackageType|RubyGems"
msgstr ""
msgid "PackageType|npm"
msgid "PackageType|npm"
msgstr ""
msgstr ""
...
...
spec/factories/packages.rb
View file @
71a89b9e
...
@@ -36,8 +36,8 @@ FactoryBot.define do
...
@@ -36,8 +36,8 @@ FactoryBot.define do
package_type
{
:rubygems
}
package_type
{
:rubygems
}
after
:create
do
|
package
|
after
:create
do
|
package
|
create
:package_file
,
:gem
,
package:
package
create
:package_file
,
package
.
processing?
?
:unprocessed_gem
:
:gem
,
package:
package
create
:package_file
,
:gemspec
,
package:
package
create
:package_file
,
:gemspec
,
package:
package
unless
package
.
processing?
end
end
trait
(
:with_metadatum
)
do
trait
(
:with_metadatum
)
do
...
...
spec/factories/packages/package_file.rb
View file @
71a89b9e
...
@@ -247,6 +247,14 @@ FactoryBot.define do
...
@@ -247,6 +247,14 @@ FactoryBot.define do
size
{
4
.
kilobytes
}
size
{
4
.
kilobytes
}
end
end
trait
(
:unprocessed_gem
)
do
package
file_fixture
{
'spec/fixtures/packages/rubygems/package.gem'
}
file_name
{
'package.gem'
}
file_sha1
{
'5fe852b2a6abd96c22c11fa1ff2fb19d9ce58b57'
}
size
{
4
.
kilobytes
}
end
trait
(
:gemspec
)
do
trait
(
:gemspec
)
do
package
package
file_fixture
{
'spec/fixtures/packages/rubygems/package.gemspec'
}
file_fixture
{
'spec/fixtures/packages/rubygems/package.gemspec'
}
...
...
spec/fixtures/api/schemas/graphql/packages/package_details.json
View file @
71a89b9e
...
@@ -23,7 +23,7 @@
...
@@ -23,7 +23,7 @@
},
},
"packageType"
:
{
"packageType"
:
{
"type"
:
[
"string"
],
"type"
:
[
"string"
],
"enum"
:
[
"MAVEN"
,
"NPM"
,
"CONAN"
,
"NUGET"
,
"PYPI"
,
"COMPOSER"
,
"GENERIC"
,
"GOLANG"
,
"DEBIAN"
]
"enum"
:
[
"MAVEN"
,
"NPM"
,
"CONAN"
,
"NUGET"
,
"PYPI"
,
"COMPOSER"
,
"GENERIC"
,
"GOLANG"
,
"
RUBYGEMS"
,
"
DEBIAN"
]
},
},
"tags"
:
{
"tags"
:
{
"type"
:
"object"
,
"type"
:
"object"
,
...
...
spec/fixtures/packages/rubygems/package-0.0.1.gem
View file @
71a89b9e
No preview for this file type
spec/fixtures/packages/rubygems/package.gem
0 → 100644
View file @
71a89b9e
File added
spec/fixtures/packages/rubygems/package.gemspec
View file @
71a89b9e
# frozen_string_literal: true
# frozen_string_literal: true
Gem
::
Specification
.
new
do
|
s
|
Gem
::
Specification
.
new
do
|
s
|
s
.
name
=
%q{package}
s
.
name
=
'package'
s
.
authors
=
[
"Tanuki Steve"
]
s
.
authors
=
[
'Tanuki Steve'
,
'Hal 9000'
]
s
.
version
=
"0.0.1"
s
.
author
=
'Tanuki Steve'
s
.
date
=
%q{2011-09-29}
s
.
version
=
'0.0.1'
s
.
summary
=
%q{package is the best}
s
.
date
=
'2011-09-29'
s
.
files
=
[
s
.
summary
=
'package is the best'
"lib/package.rb"
s
.
files
=
[
'lib/test_gem.rb'
]
]
s
.
require_paths
=
[
'lib'
]
s
.
description
=
'A test package for GitLab.'
s
.
email
=
'tanuki@not_real.com'
s
.
homepage
=
'https://gitlab.com/ruby-co/my-package'
s
.
license
=
'MIT'
s
.
metadata
=
{
'bug_tracker_uri'
=>
'https://gitlab.com/ruby-co/my-package/issues'
,
'changelog_uri'
=>
'https://gitlab.com/ruby-co/my-package/CHANGELOG.md'
,
'documentation_uri'
=>
'https://gitlab.com/ruby-co/my-package/docs'
,
'mailing_list_uri'
=>
'https://gitlab.com/ruby-co/my-package/mailme'
,
'source_code_uri'
=>
'https://gitlab.com/ruby-co/my-package'
}
s
.
bindir
=
'bin'
s
.
executables
=
[
'rake'
]
s
.
extensions
=
[
'ext/foo.rb'
]
s
.
extra_rdoc_files
=
[
'README.md'
,
'doc/userguide.md'
]
s
.
platform
=
Gem
::
Platform
::
RUBY
s
.
post_install_message
=
'Installed, thank you!'
s
.
rdoc_options
=
[
'--main'
,
'README.md'
]
s
.
required_ruby_version
=
'>= 2.7.0'
s
.
required_ruby_version
=
'>= 2.7.0'
s
.
rubygems_version
=
'>= 1.8.11'
s
.
required_rubygems_version
=
'>= 1.8.11'
s
.
require_paths
=
[
"lib"
]
s
.
requirements
=
'A high powered server or calculator'
s
.
rubygems_version
=
'1.8.09'
s
.
add_dependency
'dependency_1'
,
'~> 1.2.3'
s
.
add_dependency
'dependency_2'
,
'3.0.0'
s
.
add_dependency
'dependency_3'
,
'>= 1.0.0'
s
.
add_dependency
'dependency_4'
end
end
spec/frontend/packages/details/store/getters_spec.js
View file @
71a89b9e
...
@@ -27,6 +27,7 @@ import {
...
@@ -27,6 +27,7 @@ import {
mockPipelineInfo
,
mockPipelineInfo
,
mavenPackage
as
packageWithoutBuildInfo
,
mavenPackage
as
packageWithoutBuildInfo
,
pypiPackage
,
pypiPackage
,
rubygemsPackage
,
}
from
'
../../mock_data
'
;
}
from
'
../../mock_data
'
;
import
{
import
{
generateMavenCommand
,
generateMavenCommand
,
...
@@ -104,6 +105,7 @@ describe('Getters PackageDetails Store', () => {
...
@@ -104,6 +105,7 @@ describe('Getters PackageDetails Store', () => {
${
npmPackage
}
|
${
'
npm
'
}
${
npmPackage
}
|
${
'
npm
'
}
${
nugetPackage
}
|
${
'
NuGet
'
}
${
nugetPackage
}
|
${
'
NuGet
'
}
${
pypiPackage
}
|
${
'
PyPI
'
}
${
pypiPackage
}
|
${
'
PyPI
'
}
${
rubygemsPackage
}
|
${
'
RubyGems
'
}
`
(
`package type`
,
({
packageEntity
,
expectedResult
})
=>
{
`
(
`package type`
,
({
packageEntity
,
expectedResult
})
=>
{
beforeEach
(()
=>
setupState
({
packageEntity
}));
beforeEach
(()
=>
setupState
({
packageEntity
}));
...
...
spec/frontend/packages/mock_data.js
View file @
71a89b9e
...
@@ -134,6 +134,23 @@ export const nugetPackage = {
...
@@ -134,6 +134,23 @@ export const nugetPackage = {
},
},
};
};
export
const
rubygemsPackage
=
{
created_at
:
'
2015-12-10
'
,
id
:
4
,
name
:
'
RubyGem1
'
,
package_files
:
[],
package_type
:
'
rubygems
'
,
project_id
:
1
,
tags
:
[],
updated_at
:
'
2015-12-10
'
,
version
:
'
1.0.0
'
,
rubygems_metadatum
:
{
author
:
'
Fake Name
'
,
summary
:
'
My gem
'
,
email
:
'
tanuki@fake.com
'
,
},
};
export
const
pypiPackage
=
{
export
const
pypiPackage
=
{
created_at
:
'
2015-12-10
'
,
created_at
:
'
2015-12-10
'
,
id
:
5
,
id
:
5
,
...
...
spec/frontend/packages/shared/utils_spec.js
View file @
71a89b9e
...
@@ -38,6 +38,7 @@ describe('Packages shared utils', () => {
...
@@ -38,6 +38,7 @@ describe('Packages shared utils', () => {
${
'
npm
'
}
|
${
'
npm
'
}
${
'
npm
'
}
|
${
'
npm
'
}
${
'
nuget
'
}
|
${
'
NuGet
'
}
${
'
nuget
'
}
|
${
'
NuGet
'
}
${
'
pypi
'
}
|
${
'
PyPI
'
}
${
'
pypi
'
}
|
${
'
PyPI
'
}
${
'
rubygems
'
}
|
${
'
RubyGems
'
}
${
'
composer
'
}
|
${
'
Composer
'
}
${
'
composer
'
}
|
${
'
Composer
'
}
${
'
foo
'
}
|
${
null
}
${
'
foo
'
}
|
${
null
}
`
(
`package type`
,
({
packageType
,
expectedResult
})
=>
{
`
(
`package type`
,
({
packageType
,
expectedResult
})
=>
{
...
...
spec/services/packages/rubygems/create_dependencies_service_spec.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Packages
::
Rubygems
::
CreateDependenciesService
do
include
RubygemsHelpers
let_it_be
(
:package
)
{
create
(
:rubygems_package
)
}
let_it_be
(
:package_file
)
{
create
(
:package_file
,
:gem
)
}
let_it_be
(
:gem
)
{
gem_from_file
(
package_file
.
file
)
}
let_it_be
(
:gemspec
)
{
gem
.
spec
}
let
(
:service
)
{
described_class
.
new
(
package
,
gemspec
)
}
describe
'#execute'
do
subject
{
service
.
execute
}
it
'creates dependencies'
,
:aggregate_failures
do
expect
{
subject
}.
to
change
{
Packages
::
Dependency
.
count
}.
by
(
4
)
gemspec
.
dependencies
.
each
do
|
dependency
|
persisted_dependency
=
Packages
::
Dependency
.
find_by
(
name:
dependency
.
name
)
expect
(
persisted_dependency
.
version_pattern
).
to
eq
dependency
.
requirement
.
to_s
end
end
it
'links dependencies to the package'
do
expect
{
subject
}.
to
change
{
package
.
dependency_links
.
count
}.
by
(
4
)
expect
(
package
.
dependency_links
.
first
).
to
be_dependencies
end
end
end
spec/services/packages/rubygems/create_gemspec_service_spec.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Packages
::
Rubygems
::
CreateGemspecService
do
include
RubygemsHelpers
let_it_be
(
:package
)
{
create
(
:rubygems_package
)
}
let_it_be
(
:package_file
)
{
create
(
:package_file
,
:gem
)
}
let_it_be
(
:gem
)
{
gem_from_file
(
package_file
.
file
)
}
let_it_be
(
:gemspec
)
{
gem
.
spec
}
let
(
:service
)
{
described_class
.
new
(
package
,
gemspec
)
}
describe
'#execute'
do
subject
{
service
.
execute
}
it
'creates a new package file'
,
:aggregate_failures
do
expect
{
subject
}.
to
change
{
package
.
package_files
.
count
}.
by
(
1
)
gemspec_file
=
package
.
package_files
.
find_by
(
file_name:
"
#{
gemspec
.
name
}
.gemspec"
)
expect
(
gemspec_file
.
file
).
not_to
be_nil
expect
(
gemspec_file
.
size
).
not_to
be_nil
expect
(
gemspec_file
.
file_md5
).
not_to
be_nil
expect
(
gemspec_file
.
file_sha1
).
not_to
be_nil
expect
(
gemspec_file
.
file_sha256
).
not_to
be_nil
end
end
end
spec/services/packages/rubygems/metadata_extraction_service_spec.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
require
'spec_helper'
require
'rubygems/package'
RSpec
.
describe
Packages
::
Rubygems
::
MetadataExtractionService
do
include
RubygemsHelpers
let_it_be
(
:package
)
{
create
(
:rubygems_package
)
}
let_it_be
(
:package_file
)
{
create
(
:package_file
,
:gem
)
}
let_it_be
(
:gem
)
{
gem_from_file
(
package_file
.
file
)
}
let_it_be
(
:gemspec
)
{
gem
.
spec
}
let
(
:service
)
{
described_class
.
new
(
package
,
gemspec
)
}
describe
'#execute'
do
subject
{
service
.
execute
}
it
'creates the metadata'
do
expect
{
subject
}.
to
change
{
Packages
::
Rubygems
::
Metadatum
.
count
}.
by
(
1
)
end
it
'stores the metadata'
,
:aggregate_failures
do
subject
metadata
=
package
.
rubygems_metadatum
expect
(
metadata
.
authors
).
to
eq
(
gemspec
.
authors
.
to_json
)
expect
(
metadata
.
files
).
to
eq
(
gemspec
.
files
.
to_json
)
expect
(
metadata
.
summary
).
to
eq
(
gemspec
.
summary
)
expect
(
metadata
.
description
).
to
eq
(
gemspec
.
description
)
expect
(
metadata
.
email
).
to
eq
(
gemspec
.
email
)
expect
(
metadata
.
homepage
).
to
eq
(
gemspec
.
homepage
)
expect
(
metadata
.
licenses
).
to
eq
(
gemspec
.
licenses
.
to_json
)
expect
(
metadata
.
metadata
).
to
eq
(
gemspec
.
metadata
.
to_json
)
expect
(
metadata
.
author
).
to
eq
(
gemspec
.
author
)
expect
(
metadata
.
bindir
).
to
eq
(
gemspec
.
bindir
)
expect
(
metadata
.
executables
).
to
eq
(
gemspec
.
executables
.
to_json
)
expect
(
metadata
.
extensions
).
to
eq
(
gemspec
.
extensions
.
to_json
)
expect
(
metadata
.
extra_rdoc_files
).
to
eq
(
gemspec
.
extra_rdoc_files
.
to_json
)
expect
(
metadata
.
platform
).
to
eq
(
gemspec
.
platform
)
expect
(
metadata
.
post_install_message
).
to
eq
(
gemspec
.
post_install_message
)
expect
(
metadata
.
rdoc_options
).
to
eq
(
gemspec
.
rdoc_options
.
to_json
)
expect
(
metadata
.
require_paths
).
to
eq
(
gemspec
.
require_paths
.
to_json
)
expect
(
metadata
.
required_ruby_version
).
to
eq
(
gemspec
.
required_ruby_version
.
to_s
)
expect
(
metadata
.
required_rubygems_version
).
to
eq
(
gemspec
.
required_rubygems_version
.
to_s
)
expect
(
metadata
.
requirements
).
to
eq
(
gemspec
.
requirements
.
to_json
)
expect
(
metadata
.
rubygems_version
).
to
eq
(
gemspec
.
rubygems_version
)
end
end
end
spec/services/packages/rubygems/process_gem_service_spec.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Packages
::
Rubygems
::
ProcessGemService
do
include
ExclusiveLeaseHelpers
include
RubygemsHelpers
let_it_be_with_reload
(
:package
)
{
create
(
:rubygems_package
,
:processing
,
name:
'temp_name'
,
version:
'0.0.0'
)
}
let
(
:package_file
)
{
create
(
:package_file
,
:unprocessed_gem
,
package:
package
)
}
let
(
:gem
)
{
gem_from_file
(
package_file
.
file
)
}
let
(
:gemspec
)
{
gem
.
spec
}
let
(
:service
)
{
described_class
.
new
(
package_file
)
}
describe
'#execute'
do
subject
{
service
.
execute
}
context
'no gem file'
,
:aggregate_failures
do
let
(
:package_file
)
{
nil
}
it
'returns an error'
do
expect
(
subject
.
error?
).
to
be
(
true
)
expect
(
subject
.
message
).
to
eq
(
'Gem was not processed'
)
end
end
context
'success'
do
let
(
:sub_service
)
{
double
}
before
do
expect
(
Packages
::
Rubygems
::
MetadataExtractionService
).
to
receive
(
:new
).
with
(
package
,
gemspec
).
and_return
(
sub_service
)
expect
(
Packages
::
Rubygems
::
CreateGemspecService
).
to
receive
(
:new
).
with
(
package
,
gemspec
).
and_return
(
sub_service
)
expect
(
Packages
::
Rubygems
::
CreateDependenciesService
).
to
receive
(
:new
).
with
(
package
,
gemspec
).
and_return
(
sub_service
)
expect
(
sub_service
).
to
receive
(
:execute
).
exactly
(
3
).
times
.
and_return
(
true
)
end
it
'returns successfully'
,
:aggregate_failures
do
result
=
subject
expect
(
result
.
success?
).
to
be
true
expect
(
result
.
payload
[
:package
]).
to
eq
(
package
)
end
it
'updates the package name and version'
,
:aggregate_failures
do
expect
(
package
.
name
).
to
eq
(
'temp_name'
)
expect
(
package
.
version
).
to
eq
(
'0.0.0'
)
expect
(
package
).
to
be_processing
subject
expect
(
package
.
reload
.
name
).
to
eq
(
'package'
)
expect
(
package
.
version
).
to
eq
(
'0.0.1'
)
expect
(
package
).
to
be_default
end
it
'updates the package file name'
,
:aggregate_failures
do
expect
(
package_file
.
file_name
).
to
eq
(
'package.gem'
)
subject
expect
(
package_file
.
reload
.
file_name
).
to
eq
(
'package-0.0.1.gem'
)
end
end
context
'when the package already exists'
do
let_it_be
(
:existing_package
)
{
create
(
:rubygems_package
,
name:
'package'
,
version:
'0.0.1'
,
project:
package
.
project
)
}
let
(
:sub_service
)
{
double
}
before
do
expect
(
Packages
::
Rubygems
::
MetadataExtractionService
).
to
receive
(
:new
).
with
(
existing_package
,
gemspec
).
and_return
(
sub_service
)
expect
(
Packages
::
Rubygems
::
CreateGemspecService
).
to
receive
(
:new
).
with
(
existing_package
,
gemspec
).
and_return
(
sub_service
)
expect
(
Packages
::
Rubygems
::
CreateDependenciesService
).
to
receive
(
:new
).
with
(
existing_package
,
gemspec
).
and_return
(
sub_service
)
expect
(
sub_service
).
to
receive
(
:execute
).
exactly
(
3
).
times
.
and_return
(
true
)
end
it
'assigns the package_file to the existing package and deletes the temporary package'
,
:aggregate_failures
do
expect
(
package
).
to
receive
(
:destroy
)
expect
{
subject
}.
to
change
{
existing_package
.
package_files
.
count
}.
by
(
1
)
expect
(
package_file
.
reload
.
package
).
to
eq
(
existing_package
)
end
end
context
'sub-service failure'
do
before
do
expect
(
Packages
::
Rubygems
::
MetadataExtractionService
).
to
receive
(
:new
).
with
(
package
,
gemspec
).
and_raise
(
::
Packages
::
Rubygems
::
ProcessGemService
::
ExtractionError
.
new
(
'failure'
))
end
it
'returns an error'
do
expect
{
subject
}.
to
raise_error
(
::
Packages
::
Rubygems
::
ProcessGemService
::
ExtractionError
,
'failure'
)
end
end
context
'bad gem file'
do
before
do
expect
(
Gem
::
Package
).
to
receive
(
:new
).
and_raise
(
ArgumentError
)
end
it
'returns an error'
do
expect
{
subject
}.
to
raise_error
(
::
Packages
::
Rubygems
::
ProcessGemService
::
ExtractionError
,
'Unable to read gem file'
)
end
end
context
'without obtaining an exclusive lease'
do
let
(
:lease_key
)
{
"packages:rubygems:process_gem_service:package:
#{
package
.
id
}
"
}
before
do
stub_exclusive_lease_taken
(
lease_key
,
timeout:
1
.
hour
)
end
it
'does not perform the services'
,
:aggregate_failures
do
# The #use_file call triggers a separate lease on the package file being opened
# for use with the gem. We don't want to test that here, so we allow the call to proceed
expect
(
Gitlab
::
ExclusiveLease
).
to
receive
(
:new
).
with
(
"object_storage_migrate:Packages::PackageFile:
#{
package_file
.
id
}
"
,
anything
).
and_call_original
expect
(
Packages
::
Rubygems
::
MetadataExtractionService
).
not_to
receive
(
:new
)
expect
(
Packages
::
Rubygems
::
CreateGemspecService
).
not_to
receive
(
:new
)
expect
(
Packages
::
Rubygems
::
CreateDependenciesService
).
not_to
receive
(
:new
)
subject
expect
(
package
.
reload
.
name
).
to
eq
(
'temp_name'
)
expect
(
package
.
version
).
to
eq
(
'0.0.0'
)
expect
(
package
).
to
be_processing
expect
(
package_file
.
reload
.
file_name
).
to
eq
(
'package.gem'
)
end
end
end
end
spec/support/helpers/rubygems_helpers.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
module
RubygemsHelpers
def
gem_from_file
(
file
)
full_path
=
File
.
expand_path
(
Rails
.
root
.
join
(
'spec'
,
'fixtures'
,
'packages'
,
'rubygems'
,
file
.
filename
)
)
Gem
::
Package
.
new
(
File
.
open
(
full_path
))
end
end
spec/support/shared_examples/requests/api/rubygems_packages_shared_examples.rb
View file @
71a89b9e
...
@@ -43,6 +43,8 @@ end
...
@@ -43,6 +43,8 @@ end
RSpec
.
shared_examples
'process rubygems upload'
do
|
user_type
,
status
,
add_member
=
true
|
RSpec
.
shared_examples
'process rubygems upload'
do
|
user_type
,
status
,
add_member
=
true
|
RSpec
.
shared_examples
'creates rubygems package files'
do
RSpec
.
shared_examples
'creates rubygems package files'
do
it
'creates package files'
,
:aggregate_failures
do
it
'creates package files'
,
:aggregate_failures
do
expect
(
::
Packages
::
Rubygems
::
ExtractionWorker
).
to
receive
(
:perform_async
).
once
expect
{
subject
}
expect
{
subject
}
.
to
change
{
project
.
packages
.
count
}.
by
(
1
)
.
to
change
{
project
.
packages
.
count
}.
by
(
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
1
)
...
@@ -51,6 +53,17 @@ RSpec.shared_examples 'process rubygems upload' do |user_type, status, add_membe
...
@@ -51,6 +53,17 @@ RSpec.shared_examples 'process rubygems upload' do |user_type, status, add_membe
package_file
=
project
.
packages
.
last
.
package_files
.
reload
.
last
package_file
=
project
.
packages
.
last
.
package_files
.
reload
.
last
expect
(
package_file
.
file_name
).
to
eq
(
'package.gem'
)
expect
(
package_file
.
file_name
).
to
eq
(
'package.gem'
)
end
end
it
'returns bad request if package creation fails'
do
file_service
=
double
(
'file_service'
,
execute:
nil
)
expect
(
::
Packages
::
CreatePackageFileService
).
to
receive
(
:new
).
and_return
(
file_service
)
expect
(
::
Packages
::
Rubygems
::
ExtractionWorker
).
not_to
receive
(
:perform_async
)
subject
expect
(
response
).
to
have_gitlab_http_status
(
:bad_request
)
end
end
end
context
"for user type
#{
user_type
}
"
do
context
"for user type
#{
user_type
}
"
do
...
...
spec/workers/packages/rubygems/extraction_worker_spec.rb
0 → 100644
View file @
71a89b9e
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
Packages
::
Rubygems
::
ExtractionWorker
,
type: :worker
do
describe
'#perform'
do
let_it_be
(
:package
)
{
create
(
:rubygems_package
)
}
let
(
:package_file
)
{
package
.
package_files
.
first
}
let
(
:package_file_id
)
{
package_file
.
id
}
let
(
:package_name
)
{
'TempProject.TempPackage'
}
let
(
:package_version
)
{
'1.0.0'
}
let
(
:job_args
)
{
package_file_id
}
subject
{
described_class
.
new
.
perform
(
*
job_args
)
}
include_examples
'an idempotent worker'
do
it
'processes the gem'
,
:aggregate_failures
do
expect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
0
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
2
)
expect
(
Packages
::
Package
.
last
.
id
).
to
be
(
package
.
id
)
expect
(
package
.
name
).
not_to
be
(
package_name
)
end
end
it
'handles a processing failure'
,
:aggregate_failures
do
expect
(
::
Packages
::
Rubygems
::
ProcessGemService
).
to
receive
(
:new
)
.
and_raise
(
::
Packages
::
Rubygems
::
ProcessGemService
::
ExtractionError
)
expect
(
Gitlab
::
ErrorTracking
).
to
receive
(
:log_exception
).
with
(
instance_of
(
::
Packages
::
Rubygems
::
ProcessGemService
::
ExtractionError
),
project_id:
package
.
project_id
)
expect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
-
1
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
-
2
)
end
context
'returns when there is no package file'
do
let
(
:package_file_id
)
{
999999
}
it
'returns without action'
do
expect
(
::
Packages
::
Rubygems
::
ProcessGemService
).
not_to
receive
(
:new
)
expect
{
subject
}
.
to
change
{
Packages
::
Package
.
count
}.
by
(
0
)
.
and
change
{
Packages
::
PackageFile
.
count
}.
by
(
0
)
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment