Create Packages from Go module versions
Background
Go uses a source-based dependency management system, whereas most other dependency management systems are artifact-based. This is to say, Go dependencies are ultimately fetched directly from their source VCS repository, but dependencies in other systems are artifacts that have been uploaded to a package repository. Another unique feature of the Go ecosystem is the name of a package (excluding stdlib) must be a valid URL, sans the scheme (e.g. golang.org/x/text
). Thus, Go modules are defined by the source repository and have unique names.
For the artifact-based dependency management systems that GitLab supports (i.e. all of them except Go), database entries are created when the user pushes a package. However, Go dependency management is VCS-based, which in the context of GitLab means Git-based, thus a Git tag is a module release and there is no other way to release modules (technically anything is possible, but that would be a Bad Idea).
What does this MR do?
Per this comment, this MR adds:
-
A!41712 (merged)golang
package type forPackages::Package
- An index to ensure only one Go Package exists per (project, name, version)
- A service to create Go Packages and PackageFiles
- A worker to create Go Packages and PackageFiles asynchronously
-
Use Packages and PackageFiles as a cache for the Go proxy#254818 -
Schedule the worker from the Go proxy on cache miss#254818
Concerns and/or future work
- SQL N+1 #219308 (closed)
- Gitaly N+1 #218083, #219311
DB Migration
Up
== 20210106061254 AddUniqueIndexForGolangPackages: migrating ==================
-- transaction_open?()
-> 0.0000s
-- index_exists?(:packages_packages, [:project_id, :name, :version], {:unique=>true, :where=>"package_type = 8", :name=>"index_packages_on_project_id_name_version_unique_when_golang", :algorithm=>:concurrently})
-> 0.0098s
-- execute("SET statement_timeout TO 0")
-> 0.0002s
-- add_index(:packages_packages, [:project_id, :name, :version], {:unique=>true, :where=>"package_type = 8", :name=>"index_packages_on_project_id_name_version_unique_when_golang", :algorithm=>:concurrently})
-> 0.0119s
-- execute("RESET ALL")
-> 0.0004s
== 20210106061254 AddUniqueIndexForGolangPackages: migrated (0.0231s) =========
Down
== 20210106061254 AddUniqueIndexForGolangPackages: reverting ==================
-- transaction_open?()
-> 0.0000s
-- indexes(:packages_packages)
-> 0.0106s
-- execute("SET statement_timeout TO 0")
-> 0.0002s
-- remove_index(:packages_packages, {:algorithm=>:concurrently, :name=>"index_packages_on_project_id_name_version_unique_when_golang"})
-> 0.0033s
-- execute("RESET ALL")
-> 0.0003s
== 20210106061254 AddUniqueIndexForGolangPackages: reverted (0.0152s) =========
Queries review
Exist
https://console.postgres.ai/shared/904e8286-6c40-451b-b4a2-574a55fa78de
Query:
SELECT 1 AS one
FROM "packages_packages"
WHERE "packages_packages"."project_id" = 25155009
AND "packages_packages"."package_type" = 7
AND "packages_packages"."name" = 'Solarbreeze'
AND "packages_packages"."version" = '9.5.4'
LIMIT 1
Explain plan:
Limit (cost=0.41..3.44 rows=1 width=4) (actual time=0.948..0.949 rows=1 loops=1)
Buffers: shared read=5
I/O Timings: read=0.891
-> Index Only Scan using index_packages_on_project_id_name_version_unique_when_generic on public.packages_packages (cost=0.41..3.44 rows=1 width=4) (actual time=0.947..0.947 rows=1 loops=1)
Index Cond: ((packages_packages.project_id = 25155009) AND (packages_packages.name = 'Solarbreeze'::text) AND (packages_packages.version = '9.5.4'::text))
Heap Fetches: 1
Buffers: shared read=5
I/O Timings: read=0.891
First
https://console.postgres.ai/shared/686f2956-f8a6-4a46-9198-ab3b747dc2fe
Query:
SELECT "packages_packages".*
FROM "packages_packages"
WHERE "packages_packages"."project_id" = 25155009
AND "packages_packages"."package_type" = 7
AND "packages_packages"."name" = 'Solarbreeze'
AND "packages_packages"."version" = '9.5.4'
ORDER BY "packages_packages"."id" ASC
LIMIT 1
Explain plan:
Limit (cost=3.44..3.45 rows=1 width=84) (actual time=8.189..8.191 rows=1 loops=1)
Buffers: shared hit=3 read=4
I/O Timings: read=8.089
-> Sort (cost=3.44..3.45 rows=1 width=84) (actual time=8.187..8.188 rows=1 loops=1)
Sort Key: packages_packages.id
Sort Method: quicksort Memory: 25kB
Buffers: shared hit=3 read=4
I/O Timings: read=8.089
-> Index Scan using index_packages_on_project_id_name_version_unique_when_generic on public.packages_packages (cost=0.41..3.44 rows=1 width=84) (actual time=8.153..8.156 rows=1 loops=1)
Index Cond: ((packages_packages.project_id = 25155009) AND ((packages_packages.name)::text = 'Solarbreeze'::text) AND ((packages_packages.version)::text = '9.5.4'::text))
Buffers: shared read=4
I/O Timings: read=8.089
Does this MR meet the acceptance criteria?
Conformity
-
Changelog entry -
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides -
Database guides -
Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process.
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team