Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package gitlab-container-registry for openSUSE:Factory checked in at 2025-06-06 22:42:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gitlab-container-registry (Old) and /work/SRC/openSUSE:Factory/.gitlab-container-registry.new.19631 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gitlab-container-registry" Fri Jun 6 22:42:28 2025 rev:7 rq:1283454 version:4.23.1 Changes: -------- --- /work/SRC/openSUSE:Factory/gitlab-container-registry/gitlab-container-registry.changes 2025-06-02 22:02:07.541115766 +0200 +++ /work/SRC/openSUSE:Factory/.gitlab-container-registry.new.19631/gitlab-container-registry.changes 2025-06-06 22:42:52.756362346 +0200 @@ -1,0 +2,20 @@ +Thu Jun 05 20:10:03 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 4.23.1: + * Bug Fixes + - api/gitlab/v1: fix repository cache initialization (d135234) + - remmove cloudsql incompatible migrations (ef66c26) + - Stat call should properly handle unprefixed configurations in + s3_v2 storage driver (4b67a75) + * Reverts + - revert 7fed33f9 (ede0ad3) + - revert ef66c261 (d00e168) + * Build + - deps: update module github.com/alicebob/miniredis/v2 to + v2.35.0 (f554f29) + - deps: update module google.golang.org/api to v0.235.0 + (5313f8f) + - deps: update module google.golang.org/api to v0.236.0 + (38034e4) + +------------------------------------------------------------------- Old: ---- gitlab-container-registry-4.23.0.obscpio New: ---- gitlab-container-registry-4.23.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gitlab-container-registry.spec ++++++ --- /var/tmp/diff_new_pack.TeE0wt/_old 2025-06-06 22:42:54.200422192 +0200 +++ /var/tmp/diff_new_pack.TeE0wt/_new 2025-06-06 22:42:54.204422358 +0200 @@ -17,7 +17,7 @@ Name: gitlab-container-registry -Version: 4.23.0 +Version: 4.23.1 Release: 0 Summary: The GitLab Container Registry License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.TeE0wt/_old 2025-06-06 22:42:54.236423684 +0200 +++ /var/tmp/diff_new_pack.TeE0wt/_new 2025-06-06 22:42:54.240423850 +0200 @@ -3,7 +3,7 @@ <param name="url">https://gitlab.com/gitlab-org/container-registry.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v4.23.0-gitlab</param> + <param name="revision">v4.23.1-gitlab</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)-gitlab</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.TeE0wt/_old 2025-06-06 22:42:54.264424844 +0200 +++ /var/tmp/diff_new_pack.TeE0wt/_new 2025-06-06 22:42:54.268425010 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://gitlab.com/gitlab-org/container-registry.git</param> - <param name="changesrevision">ff993bd5c4889e5a2943c4da7b9456487564dba5</param></service></servicedata> + <param name="changesrevision">89261ccc3ffb86dbc02d374380f9ae986d4c013b</param></service></servicedata> (No newline at EOF) ++++++ gitlab-container-registry-4.23.0.obscpio -> gitlab-container-registry-4.23.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/CHANGELOG.md new/gitlab-container-registry-4.23.1/CHANGELOG.md --- old/gitlab-container-registry-4.23.0/CHANGELOG.md 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/CHANGELOG.md 2025-06-05 18:31:56.000000000 +0200 @@ -1,3 +1,22 @@ +## [4.23.1](https://gitlab.com/gitlab-org/container-registry/compare/v4.23.0-gitlab...v4.23.1-gitlab) (2025-06-05) + +### 🐛 Bug Fixes 🐛 + +* **api/gitlab/v1:** fix repository cache initialization ([d135234](https://gitlab.com/gitlab-org/container-registry/commit/d1352341cee75fd185f0a67b1f75f2599fc68057)) +* remmove cloudsql incompatible migrations ([ef66c26](https://gitlab.com/gitlab-org/container-registry/commit/ef66c261a2d8e3433a7c0b6be24c90e8b32d1538)) +* Stat call should properly handle unprefixed configurations in s3_v2 storage driver ([4b67a75](https://gitlab.com/gitlab-org/container-registry/commit/4b67a753fd4232d5898fc36abddd15b4d0aa61b4)) + +### ⏮️️ Reverts ⏮️️ + +* revert 7fed33f9 ([ede0ad3](https://gitlab.com/gitlab-org/container-registry/commit/ede0ad3ae0642477413b6d99e2e6cce681712e9b)) +* revert ef66c261a2d8e3433a7c0b6be24c90e8b32d1538 ([d00e168](https://gitlab.com/gitlab-org/container-registry/commit/d00e1684606eb3b7c62b42db1e9ffd435c2fb6a6)) + +### ⚙️ Build ⚙️ + +* **deps:** update module github.com/alicebob/miniredis/v2 to v2.35.0 ([f554f29](https://gitlab.com/gitlab-org/container-registry/commit/f554f291f63df19b87fcfe9b88bad0de00ae9721)) +* **deps:** update module google.golang.org/api to v0.235.0 ([5313f8f](https://gitlab.com/gitlab-org/container-registry/commit/5313f8f87d6736a0d12d89a62c3f34afb27c6269)) +* **deps:** update module google.golang.org/api to v0.236.0 ([38034e4](https://gitlab.com/gitlab-org/container-registry/commit/38034e4723d2b4e120584dc4c469a67310763e3b)) + ## [4.23.0](https://gitlab.com/gitlab-org/container-registry/compare/v4.22.0-gitlab...v4.23.0-gitlab) (2025-06-02) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/go.mod new/gitlab-container-registry-4.23.1/go.mod --- old/gitlab-container-registry-4.23.0/go.mod 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/go.mod 2025-06-05 18:31:56.000000000 +0200 @@ -13,7 +13,7 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/Shopify/toxiproxy/v2 v2.12.0 - github.com/alicebob/miniredis/v2 v2.34.0 + github.com/alicebob/miniredis/v2 v2.35.0 github.com/aws/aws-sdk-go v1.55.5 github.com/aws/aws-sdk-go-v2 v1.36.3 github.com/aws/aws-sdk-go-v2/config v1.29.14 @@ -59,7 +59,7 @@ golang.org/x/oauth2 v0.30.0 golang.org/x/sync v0.14.0 golang.org/x/time v0.11.0 - google.golang.org/api v0.234.0 + google.golang.org/api v0.236.0 gopkg.in/yaml.v2 v2.4.0 ) @@ -86,7 +86,6 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect @@ -210,8 +209,8 @@ golang.org/x/text v0.25.0 // indirect google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 // indirect - google.golang.org/grpc v1.72.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect + google.golang.org/grpc v1.72.2 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/go.sum new/gitlab-container-registry-4.23.1/go.sum --- old/gitlab-container-registry-4.23.0/go.sum 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/go.sum 2025-06-05 18:31:56.000000000 +0200 @@ -132,10 +132,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= -github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= -github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= +github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI= +github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -1179,8 +1177,8 @@ google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.234.0 h1:d3sAmYq3E9gdr2mpmiWGbm9pHsA/KJmyiLkwKfHBqU4= -google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.236.0 h1:CAiEiDVtO4D/Qja2IA9VzlFrgPnK3XVMmRoJZlSWbc0= +google.golang.org/api v0.236.0/go.mod h1:X1WF9CU2oTc+Jml1tiIxGmWFK/UZezdqEu09gcxZAj4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1244,8 +1242,8 @@ google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2 h1:vPV0tzlsK6EzEDHNNH5sa7Hs9bd7iXR7B1tSiPepkV0= google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9 h1:IkAfh6J/yllPtpYFU0zZN1hUPYdT0ogkBT/9hMxHjvg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1275,8 +1273,8 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/registry/datastore/migrations/premigrations/20250421061041_create_trigger_for_media_type_id_convert_to_bigint.go new/gitlab-container-registry-4.23.1/registry/datastore/migrations/premigrations/20250421061041_create_trigger_for_media_type_id_convert_to_bigint.go --- old/gitlab-container-registry-4.23.0/registry/datastore/migrations/premigrations/20250421061041_create_trigger_for_media_type_id_convert_to_bigint.go 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/registry/datastore/migrations/premigrations/20250421061041_create_trigger_for_media_type_id_convert_to_bigint.go 2025-06-05 18:31:56.000000000 +0200 @@ -22,10 +22,22 @@ LANGUAGE plpgsql;`, // Create the trigger to fire on INSERT and UPDATE - `CREATE TRIGGER set_media_type_id_convert_to_bigint - BEFORE INSERT OR UPDATE ON manifests - FOR EACH ROW - EXECUTE PROCEDURE set_media_type_id_convert_to_bigint ()`, + `DO $$ + BEGIN + IF NOT EXISTS ( + SELECT + 1 + FROM + pg_trigger + WHERE + tgname = 'set_media_type_id_convert_to_bigint') THEN + CREATE TRIGGER set_media_type_id_convert_to_bigint + BEFORE INSERT OR UPDATE ON manifests + FOR EACH ROW + EXECUTE PROCEDURE set_media_type_id_convert_to_bigint (); + END IF; + END + $$`, }, Down: []string{ "DROP TRIGGER IF EXISTS set_media_type_id_convert_to_bigint ON manifests", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/registry/handlers/app.go new/gitlab-container-registry-4.23.1/registry/handlers/app.go --- old/gitlab-container-registry-4.23.0/registry/handlers/app.go 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/registry/handlers/app.go 2025-06-05 18:31:56.000000000 +0200 @@ -1603,6 +1603,13 @@ ctx.queueBridge = app.queueBridge(ctx, r) } + // Initialize repository cache + if app.redisCache != nil { + ctx.repoCache = datastore.NewCentralRepositoryCache(app.redisCache) + } else { + ctx.repoCache = datastore.NewSingleRepositoryCache() + } + dispatch(ctx, r).ServeHTTP(w, r) // Automated error response handling here. Handlers may return their diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/registry/handlers/app_test.go new/gitlab-container-registry-4.23.1/registry/handlers/app_test.go --- old/gitlab-container-registry-4.23.0/registry/handlers/app_test.go 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/registry/handlers/app_test.go 2025-06-05 18:31:56.000000000 +0200 @@ -15,12 +15,17 @@ "testing" "time" - "github.com/docker/distribution/internal/feature" + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" "github.com/docker/distribution/configuration" dcontext "github.com/docker/distribution/context" + "github.com/docker/distribution/internal/feature" "github.com/docker/distribution/reference" "github.com/docker/distribution/registry/api/errcode" + v1 "github.com/docker/distribution/registry/api/gitlab/v1" "github.com/docker/distribution/registry/api/urls" v2 "github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/registry/auth" @@ -28,16 +33,13 @@ "github.com/docker/distribution/registry/datastore" dmocks "github.com/docker/distribution/registry/datastore/mocks" imocks "github.com/docker/distribution/registry/internal/mocks" + iredis "github.com/docker/distribution/registry/internal/redis" "github.com/docker/distribution/registry/internal/testutil" "github.com/docker/distribution/registry/storage" memorycache "github.com/docker/distribution/registry/storage/cache/memory" _ "github.com/docker/distribution/registry/storage/driver/filesystem" "github.com/docker/distribution/registry/storage/driver/testdriver" dtestutil "github.com/docker/distribution/testutil" - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" ) // TestAppDistribtionDispatcher builds an application with a test dispatcher and @@ -1041,3 +1043,81 @@ }) } } + +// TestDispatcherGitlab_RepoCacheInitialization ensures that ctx.repoCache is properly initialized +// when the database is enabled in the GitLab v1 API dispatcher. +func TestDispatcherGitlab_RepoCacheInitialization(t *testing.T) { + driver := testdriver.New() + ctx := dtestutil.NewContextWithLogger(t) + registry, err := storage.NewRegistry(ctx, driver) + require.NoError(t, err) + + testCases := []struct { + name string + redisCache bool + expectedType any + }{ + { + name: "with redis cache", + redisCache: true, + expectedType: datastore.NewCentralRepositoryCache(&iredis.Cache{}), + }, + { + name: "without redis cache", + redisCache: false, + expectedType: datastore.NewSingleRepositoryCache(), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + app := &App{ + Config: &configuration.Configuration{ + Database: configuration.Database{ + Enabled: true, + }, + }, + Context: ctx, + driver: driver, + registry: registry, + // Bypass authorization logic + accessController: nil, + } + + if tc.redisCache { + // Create a mock Redis cache + app.redisCache = &iredis.Cache{} + } + + // Initialize the app's router to get proper GitLab v1 routes + require.NoError(t, app.initMetaRouter()) + + // Create a test dispatcher that captures the context + var capturedContext *Context + testDispatcher := func(ctx *Context, _ *http.Request) http.Handler { + capturedContext = ctx + return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }) + } + + // Register our test dispatcher for the GitLab v1 base route + app.registerGitlab(v1.Base, testDispatcher) + + // Create a test request to the GitLab v1 base endpoint + req := httptest.NewRequest(http.MethodGet, v1.Base.Path, nil) + w := httptest.NewRecorder() + + // Use the app's router to serve the request, which will properly set up route context + app.ServeHTTP(w, req) + + // Verify the context was captured + require.NotNil(t, capturedContext, "context should be captured") + + // Check repoCache initialization + require.NotNil(t, capturedContext.repoCache, "repoCache should not be nil when database is enabled") + // Verify the type of cache based on Redis availability + require.IsType(t, tc.expectedType, capturedContext.repoCache, "repoCache should be of expected type") + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/registry/storage/driver/s3-aws/v2/s3.go new/gitlab-container-registry-4.23.1/registry/storage/driver/s3-aws/v2/s3.go --- old/gitlab-container-registry-4.23.0/registry/storage/driver/s3-aws/v2/s3.go 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/registry/storage/driver/s3-aws/v2/s3.go 2025-06-05 18:31:56.000000000 +0200 @@ -429,11 +429,18 @@ } func (d *driver) statHead(ctx context.Context, path string) (*storagedriver.FileInfoFields, error) { + // NOTE(prozlach): This is to cover for the cases when the rootDirectory of + // the driver is either "" or "/". + key := d.s3Path(path) + if key == "" { + key = "/" + } + resp, err := d.S3.HeadObject( ctx, &s3.HeadObjectInput{ Bucket: ptr.String(d.Bucket), - Key: ptr.String(d.s3Path(path)), + Key: &key, }, ) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/registry/storage/driver/testsuites/testsuites.go new/gitlab-container-registry-4.23.1/registry/storage/driver/testsuites/testsuites.go --- old/gitlab-container-registry-4.23.0/registry/storage/driver/testsuites/testsuites.go 2025-06-02 17:00:01.000000000 +0200 +++ new/gitlab-container-registry-4.23.1/registry/storage/driver/testsuites/testsuites.go 2025-06-05 18:31:56.000000000 +0200 @@ -752,6 +752,9 @@ if s.StorageDriver.Name() == "inmemory" { s.T().Skip("In-memory driver is known to have OOM issues with large uploads.") } + if s.StorageDriver.Name() == "filesystem" { + s.T().Skip("filesystem driver tests are running on tmpfs and it does not do chunking so this test would not bring much value") + } if slices.Contains([]string{s3_common.V1DriverName, s3_common.V1DriverNameAlt}, s.StorageDriver.Name()) { s.T().Skip("S3 v1 driver has chunk size limitations which aren't planned to be fixed") } @@ -2011,117 +2014,165 @@ err := s.StorageDriver.PutContent(s.ctx, filePath, contentA) require.NoError(s.T(), err) - err = s.StorageDriver.PutContent(s.ctx, filePathAux, contentA) require.NoError(s.T(), err) - defer s.deletePath(s.StorageDriver, firstPart(dirPath)) + if s.StorageDriver.Name() != "filesystem" { + err = s.StorageDriverRootless.PutContent(s.ctx, filePath, contentA) + require.NoError(s.T(), err) + err = s.StorageDriverRootless.PutContent(s.ctx, filePathAux, contentA) + require.NoError(s.T(), err) + defer s.deletePath(s.StorageDriverRootless, firstPart(dirPath)) + } + // Call to stat on root directory. The storage healthcheck performs this // exact call to Stat. // PathNotFoundErrors are not considered health check failures. Some // drivers will return a not found here, while others will not return an // error at all. If we get an error, ensure it's a not found. - s.Run("RootDirectory", func() { - fi, err := s.StorageDriver.Stat(s.ctx, "/") - if err != nil { - assert.ErrorAs(s.T(), err, new(storagedriver.PathNotFoundError)) - } else { - assert.NotNil(s.T(), fi) - assert.Equal(s.T(), "/", fi.Path()) - assert.True(s.T(), fi.IsDir()) + for _, name := range []string{"prefixed", "unprefixed"} { + var drv storagedriver.StorageDriver + switch name { + case "prefixed": + drv = s.StorageDriver + case "unprefixed": + drv = s.StorageDriverRootless } - }) - s.Run("NonExistentDir", func() { - fi, err := s.StorageDriver.Stat(s.ctx, dirPath+"foo") - require.Error(s.T(), err) - assert.ErrorIs(s.T(), err, storagedriver.PathNotFoundError{ // nolint: testifylint - DriverName: s.StorageDriver.Name(), - Path: dirPath + "foo", + s.Run(fmt.Sprintf("RootDirectory - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } + + fi, err := drv.Stat(s.ctx, "/") + if err != nil { + assert.ErrorAs(s.T(), err, new(storagedriver.PathNotFoundError)) + } else { + assert.NotNil(s.T(), fi) + assert.Equal(s.T(), "/", fi.Path()) + assert.True(s.T(), fi.IsDir()) + } }) - assert.Nil(s.T(), fi) - }) - s.Run("NonExistentPath", func() { - fi, err := s.StorageDriver.Stat(s.ctx, filePath+"bar") - require.Error(s.T(), err) - assert.ErrorIs(s.T(), err, storagedriver.PathNotFoundError{ // nolint: testifylint - DriverName: s.StorageDriver.Name(), - Path: filePath + "bar", + s.Run(fmt.Sprintf("NonExistentDir - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } + + fi, err := drv.Stat(s.ctx, dirPath+"foo") + require.Error(s.T(), err) + assert.ErrorIs(s.T(), err, storagedriver.PathNotFoundError{ // nolint: testifylint + DriverName: drv.Name(), + Path: dirPath + "foo", + }) + assert.Nil(s.T(), fi) }) - assert.Nil(s.T(), fi) - }) - s.Run("FileExists", func() { - fi, err := s.StorageDriver.Stat(s.ctx, filePath) - require.NoError(s.T(), err) - require.NotNil(s.T(), fi) - assert.Equal(s.T(), filePath, fi.Path()) - assert.Equal(s.T(), int64(len(contentA)), fi.Size()) - assert.False(s.T(), fi.IsDir()) - }) + s.Run(fmt.Sprintf("NonExistentPath - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } - s.Run("ModTime", func() { - fi, err := s.StorageDriver.Stat(s.ctx, filePath) - require.NoError(s.T(), err) - assert.NotNil(s.T(), fi) - createdTime := fi.ModTime() + fi, err := drv.Stat(s.ctx, filePath+"bar") + require.Error(s.T(), err) + assert.ErrorIs(s.T(), err, storagedriver.PathNotFoundError{ // nolint: testifylint + DriverName: drv.Name(), + Path: filePath + "bar", + }) + assert.Nil(s.T(), fi) + }) - // Sleep and modify the file - time.Sleep(time.Second * 10) - err = s.StorageDriver.PutContent(s.ctx, filePath, contentB) - require.NoError(s.T(), err) + s.Run(fmt.Sprintf("FileExists - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } - fi, err = s.StorageDriver.Stat(s.ctx, filePath) - require.NoError(s.T(), err) - require.NotNil(s.T(), fi) - modTime := fi.ModTime() + fi, err := drv.Stat(s.ctx, filePath) + require.NoError(s.T(), err) + require.NotNil(s.T(), fi) + assert.Equal(s.T(), filePath, fi.Path()) + assert.Equal(s.T(), int64(len(contentA)), fi.Size()) + assert.False(s.T(), fi.IsDir()) + }) - // Check if the modification time is after the creation time. - // In case of cloud storage services, storage frontend nodes might have - // time drift between them, however that should be solved with sleeping - // before update. - assert.Greaterf( - s.T(), - modTime, - createdTime, - "modtime (%s) is before the creation time (%s)", modTime, createdTime, - ) - }) + s.Run(fmt.Sprintf("ModTime - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } - // Call on directory with one "file" - // (do not check ModTime as dirs don't need to support it) - s.Run("DirWithFile", func() { - fi, err := s.StorageDriver.Stat(s.ctx, dirPath) - require.NoError(s.T(), err) - require.NotNil(s.T(), fi) - assert.Equal(s.T(), dirPath, fi.Path()) - assert.Zero(s.T(), fi.Size()) - assert.True(s.T(), fi.IsDir()) - }) + fi, err := drv.Stat(s.ctx, filePath) + require.NoError(s.T(), err) + assert.NotNil(s.T(), fi) + createdTime := fi.ModTime() - // Call on directory with another "subdirectory" - s.Run("DirWithSubDir", func() { - fi, err := s.StorageDriver.Stat(s.ctx, dirPathBase) - require.NoError(s.T(), err) - require.NotNil(s.T(), fi) - assert.Equal(s.T(), dirPathBase, fi.Path()) - assert.Zero(s.T(), fi.Size()) - assert.True(s.T(), fi.IsDir()) - }) + // Sleep and modify the file + time.Sleep(time.Second * 10) + err = drv.PutContent(s.ctx, filePath, contentB) + require.NoError(s.T(), err) + + fi, err = drv.Stat(s.ctx, filePath) + require.NoError(s.T(), err) + require.NotNil(s.T(), fi) + modTime := fi.ModTime() + + // Check if the modification time is after the creation time. + // In case of cloud storage services, storage frontend nodes might have + // time drift between them, however that should be solved with sleeping + // before update. + assert.Greaterf( + s.T(), + modTime, + createdTime, + "modtime (%s) is before the creation time (%s)", modTime, createdTime, + ) + }) - // Call on a partial name of the directory. This should result in - // not-found, as partial match is still not a match for a directory. - s.Run("DirPartialPrefix", func() { - fi, err := s.StorageDriver.Stat(s.ctx, partialPath) - require.Error(s.T(), err) - assert.ErrorIs(s.T(), err, storagedriver.PathNotFoundError{ // nolint: testifylint - DriverName: s.StorageDriver.Name(), - Path: partialPath, + // Call on directory with one "file" + // (do not check ModTime as dirs don't need to support it) + s.Run(fmt.Sprintf("DirWithFile - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } + + fi, err := drv.Stat(s.ctx, dirPath) + require.NoError(s.T(), err) + require.NotNil(s.T(), fi) + assert.Equal(s.T(), dirPath, fi.Path()) + assert.Zero(s.T(), fi.Size()) + assert.True(s.T(), fi.IsDir()) }) - assert.Nil(s.T(), fi) - }) + + // Call on directory with another "subdirectory" + s.Run(fmt.Sprintf("DirWithSubDir - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } + + fi, err := drv.Stat(s.ctx, dirPathBase) + require.NoError(s.T(), err) + require.NotNil(s.T(), fi) + assert.Equal(s.T(), dirPathBase, fi.Path()) + assert.Zero(s.T(), fi.Size()) + assert.True(s.T(), fi.IsDir()) + }) + + // Call on a partial name of the directory. This should result in + // not-found, as partial match is still not a match for a directory. + s.Run(fmt.Sprintf("DirPartialPrefix - %s", name), func() { + if s.StorageDriver.Name() == "filesystem" && name == "unprefixed" { + s.T().Skip("filesystem driver does not support prefix-less operation") + } + + fi, err := drv.Stat(s.ctx, partialPath) + require.Error(s.T(), err) + assert.ErrorIs(s.T(), err, storagedriver.PathNotFoundError{ // nolint: testifylint + DriverName: drv.Name(), + Path: partialPath, + }) + assert.Nil(s.T(), fi) + }) + } } // TestPutContentMultipleTimes checks that if storage driver can overwrite the content diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gitlab-container-registry-4.23.0/script/repo_health.py new/gitlab-container-registry-4.23.1/script/repo_health.py --- old/gitlab-container-registry-4.23.0/script/repo_health.py 1970-01-01 01:00:00.000000000 +0100 +++ new/gitlab-container-registry-4.23.1/script/repo_health.py 2025-06-05 18:31:56.000000000 +0200 @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +import os +import re +import subprocess +from datetime import datetime, timedelta + + +def parse_codeowners(codeowners_path): + """Parse the CODEOWNERS file and return a list of patterns.""" + if not os.path.exists(codeowners_path): + print(f"Error: CODEOWNERS file not found at {codeowners_path}") + return [] + + patterns = [] + # current_section = None + + with open(codeowners_path, 'r') as f: + for line in f: + # Skip empty lines + line = line.strip() + if not line: + continue + + # Skip comments + if line.startswith('#'): + continue + + # Check for section headers [Section Name] + section_match = re.match(r'^\[(.*?)\]', line) + if section_match: + # current_section = section_match.group(1).strip() + # Skip section headers, they're not patterns + continue + + # Extract the pattern (first part before the owners) + # Owners start with @ symbol + parts = line.split('@', 1) + + if len(parts) >= 1: + # The pattern is everything before the first @ symbol + pattern = parts[0].strip() + + # Special case: if pattern is exactly "/" it means the whole repo and + # we do not count it as this is a catch-all for files without owners. + # Skip empty patterns + if not pattern or pattern == "/": + continue + + # Add pattern to the list + patterns.append(pattern) + + # Additional debug information (remove in production) + # print(f"Section: {current_section}, Pattern: {pattern}") + + return patterns + + +def is_file_covered(file_path, codeowners_patterns): + """Check if a file is covered by any specific pattern in CODEOWNERS.""" + for pattern in codeowners_patterns: + regex_pattern = pattern.replace( + '.', '\\.').replace('*', '.*').replace('?', '.') + + if pattern.startswith('/'): + regex_pattern = "^" + regex_pattern.lstrip('/') + + if re.search(regex_pattern, file_path): + return True + + return False + + +def count_lines_in_file(file_path): + """Count the number of lines in a file.""" + try: + with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: + return sum(1 for _ in f) + except Exception as e: + print(f"Error counting lines in {file_path}: {e}") + return 0 + + +def get_commits_in_last_year(): + """Get all commits from the last 12 months.""" + one_year_ago = (datetime.now() - timedelta(days=365)).strftime('%Y-%m-%d') + try: + result = subprocess.run( + ['git', 'log', '--since', one_year_ago, '--format=%H'], + capture_output=True, text=True, check=True + ) + commits = result.stdout.strip().split('\n') + return [c for c in commits if c] # Filter out empty strings + except subprocess.CalledProcessError as e: + print(f"Error getting commits: {e}") + return [] + + +def get_files_changed_in_commit(commit_hash): + """Get all files changed in a specific commit.""" + try: + result = subprocess.run( + ['git', 'diff-tree', '--no-commit-id', + '--name-only', '-r', commit_hash], + capture_output=True, text=True, check=True + ) + files = result.stdout.strip().split('\n') + return [f for f in files if f] # Filter out empty strings + except subprocess.CalledProcessError as e: + print(f"Error getting files for commit {commit_hash}: {e}") + return [] + + +def get_repo_root(): + """Determine the repository root.""" + try: + result = subprocess.run( + ['git', 'rev-parse', '--show-toplevel'], + capture_output=True, text=True, check=True + ) + return result.stdout.strip() + except subprocess.CalledProcessError: + # If git command fails, return relative path based on script location + script_dir = os.path.dirname(os.path.abspath(__file__)) + # Go up one level from script directory + return os.path.dirname(script_dir) + + +def main(): + # Get repository root + repo_root = get_repo_root() + print(f"Repository root: {repo_root}") + + # Path to CODEOWNERS file relative to script + codeowners_path = os.path.normpath( + os.path.join(repo_root, '.gitlab/CODEOWNERS')) + + print(f"Looking for CODEOWNERS file at: {codeowners_path}") + + # Parse CODEOWNERS file + codeowners_patterns = parse_codeowners(codeowners_path) + if not codeowners_patterns: + print("No valid patterns found in CODEOWNERS file") + return + + print(f"Found {len(codeowners_patterns)} patterns in CODEOWNERS file") + + # Change directory to repository root + os.chdir(repo_root) + + # Find all Go files in the repository + go_files = [] + for root, _, files in os.walk('.'): + if '.git' in root: + continue + for file in files: + if file.endswith('.go') and not file.endswith('_test.go'): + file_path = os.path.join(root, file) + go_files.append(file_path) + + # Count lines of code and check coverage + total_loc = 0 + covered_loc = 0 + covered_files = [] + uncovered_files = [] + + for file_path in go_files: + # Normalize path for pattern matching + normalized_path = file_path + if normalized_path.startswith('./'): + normalized_path = normalized_path[2:] + + # Count lines + loc = count_lines_in_file(file_path) + total_loc += loc + + # Check if covered by CODEOWNERS + if is_file_covered(normalized_path, codeowners_patterns): + covered_loc += loc + covered_files.append(normalized_path) + else: + uncovered_files.append(normalized_path) + + # Get commits in the last 12 months + commits = get_commits_in_last_year() + total_commits = len(commits) + + # Count commits touching uncovered files + uncovered_commits = set() + for commit in commits: + changed_files = get_files_changed_in_commit(commit) + # Normalize paths + changed_files = [f if not f.startswith( + './') else f[2:] for f in changed_files] + # Filter for Go files only + changed_go_files = [f for f in changed_files if f.endswith('.go')] + + # Check if any uncovered file was touched + for changed_file in changed_go_files: + if changed_file in uncovered_files: + uncovered_commits.add(commit) + break + + # Print results + print(f"Total Go files: {len(go_files)}") + print( + f"Files covered by CODEOWNERS: {len(covered_files)} ({len(covered_files)/len(go_files)*100:.2f}%)") + print( + f"Files not covered by CODEOWNERS: {len(uncovered_files)} ({len(uncovered_files)/len(go_files)*100:.2f}%)") + print() + print(f"Total lines of Go code: {total_loc}") + print( + f"Lines covered by CODEOWNERS: {covered_loc} ({covered_loc/total_loc*100:.2f}%)") + print( + f"Lines not covered by CODEOWNERS: {total_loc - covered_loc} ({(total_loc - covered_loc)/total_loc*100:.2f}%)") + print() + print(f"Total commits in the last 12 months: {total_commits}") + uncovered_commit_count = len(uncovered_commits) + print( + f"Commits touching files not covered by CODEOWNERS: {uncovered_commit_count} ({uncovered_commit_count/total_commits*100:.2f}%)") + + +if __name__ == "__main__": + main() ++++++ gitlab-container-registry.obsinfo ++++++ --- /var/tmp/diff_new_pack.TeE0wt/_old 2025-06-06 22:42:55.312468278 +0200 +++ /var/tmp/diff_new_pack.TeE0wt/_new 2025-06-06 22:42:55.316468443 +0200 @@ -1,5 +1,5 @@ name: gitlab-container-registry -version: 4.23.0 -mtime: 1748876401 -commit: ff993bd5c4889e5a2943c4da7b9456487564dba5 +version: 4.23.1 +mtime: 1749141116 +commit: 89261ccc3ffb86dbc02d374380f9ae986d4c013b ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/gitlab-container-registry/vendor.tar.gz /work/SRC/openSUSE:Factory/.gitlab-container-registry.new.19631/vendor.tar.gz differ: char 13, line 1