1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
# frozen_string_literal: true
module Packages
module Nuget
class UpdatePackageFromMetadataService
include Gitlab::Utils::StrongMemoize
include ExclusiveLeaseGuard
# used by ExclusiveLeaseGuard
DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
SYMBOL_PACKAGE_IDENTIFIER = 'SymbolsPackage'
INVALID_METADATA_ERROR_MESSAGE = 'package name, version, authors and/or description not found in metadata'
INVALID_METADATA_ERROR_SYMBOL_MESSAGE = 'package name, version and/or description not found in metadata'
MISSING_MATCHING_PACKAGE_ERROR_MESSAGE = 'symbol package is invalid, matching package does not exist'
InvalidMetadataError = Class.new(StandardError)
ZipError = Class.new(StandardError)
def initialize(package_file)
@package_file = package_file
end
def execute
unless valid_metadata?
error_message = symbol_package? ? INVALID_METADATA_ERROR_SYMBOL_MESSAGE : INVALID_METADATA_ERROR_MESSAGE
raise InvalidMetadataError, error_message
end
try_obtain_lease do
@package_file.transaction do
process_package_update
end
end
rescue ActiveRecord::RecordInvalid => e
raise InvalidMetadataError, e.message
rescue Zip::Error
raise ZipError, 'Could not open the .nupkg file'
end
private
def process_package_update
package_to_destroy = nil
target_package = @package_file.package
if existing_package
package_to_destroy = @package_file.package
target_package = existing_package
else
if symbol_package?
raise InvalidMetadataError, MISSING_MATCHING_PACKAGE_ERROR_MESSAGE
end
update_linked_package
end
build_infos = package_to_destroy&.build_infos || []
update_package(target_package, build_infos)
update_symbol_files(target_package, package_to_destroy) if symbol_package?
::Packages::UpdatePackageFileService.new(@package_file, package_id: target_package.id, file_name: package_filename)
.execute
package_to_destroy&.destroy!
end
def update_package(package, build_infos)
return if symbol_package?
::Packages::Nuget::SyncMetadatumService
.new(package, metadata.slice(:authors, :description, :project_url, :license_url, :icon_url))
.execute
::Packages::UpdateTagsService
.new(package, package_tags)
.execute
package.build_infos << build_infos if build_infos.any?
rescue StandardError => e
raise InvalidMetadataError, e.message
end
def update_symbol_files(package, package_to_destroy)
package_to_destroy.nuget_symbols.update_all(package_id: package.id)
end
def valid_metadata?
fields = [package_name, package_version, package_description]
fields << package_authors unless symbol_package?
fields.all?(&:present?)
end
def update_linked_package
@package_file.package.update!(
name: package_name,
version: package_version,
status: :default
)
::Packages::Nuget::CreateDependencyService.new(@package_file.package, package_dependencies)
.execute
@package_file.package
end
def existing_package
::Packages::Nuget::PackageFinder
.new(
nil,
@package_file.project,
package_name: package_name,
package_version: package_version
)
.execute
.first
end
strong_memoize_attr :existing_package
def package_name
metadata[:package_name]
end
def package_version
metadata[:package_version]
end
def package_dependencies
metadata.fetch(:package_dependencies, [])
end
def package_tags
metadata.fetch(:package_tags, [])
end
def package_types
metadata.fetch(:package_types, [])
end
def package_authors
metadata[:authors]
end
def package_description
metadata[:description]
end
def symbol_package?
package_types.include?(SYMBOL_PACKAGE_IDENTIFIER)
end
def metadata
::Packages::Nuget::MetadataExtractionService.new(@package_file).execute.payload
end
strong_memoize_attr :metadata
def package_filename
"#{package_name.downcase}.#{package_version.downcase}.#{symbol_package? ? 'snupkg' : 'nupkg'}"
end
# used by ExclusiveLeaseGuard
def lease_key
package_id = existing_package ? existing_package.id : @package_file.package_id
"packages:nuget:update_package_from_metadata_service:package:#{package_id}"
end
# used by ExclusiveLeaseGuard
def lease_timeout
DEFAULT_LEASE_TIMEOUT
end
end
end
end
|