detached 5dbd27f

fix(lint): check ignored close and remove errors, simplify release conditions

commit
5dbd27fc45163a9fccc5f6cf45c55ed6935ad7d3
author
brice · · 2026-10-21 18:33 UTC
parent
b869944
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
checks
8/8
12 files · +31 -30
M internal/adapters/blobdisk/blobdisk.go +9 -9
@@ -183,7 +183,7 @@ func (s *Store) Put(ctx context.Context, key string, r io.Reader, size int64) (p
183183 if e != nil {
184184 return ports.BlobInfo{}, e
185185 }
186- defer os.Remove(f.Name())
186+ defer func() { _ = os.Remove(f.Name()) }()
187187 h := sha256.New()
188188 n, e := io.Copy(io.MultiWriter(f, h), ctxReader{ctx, r})
189189 if e == nil && n != size {
@@ -256,7 +256,7 @@ func (s *Store) Open(ctx context.Context, key string, offset, length int64) (io.
256256 return nil, info, translate(e)
257257 }
258258 if _, e = f.Seek(offset, io.SeekStart); e != nil {
259- f.Close()
259+ _ = f.Close()
260260 return nil, info, e
261261 }
262262 var r io.Reader = ctxReader{ctx, f}
@@ -364,15 +364,15 @@ func (s *Store) NewMultipart(ctx context.Context, key string) (ports.MultipartUp
364364 return nil, e
365365 }
366366 if e := writeMetadata(stage, metadata{key, time.Now().UTC()}); e != nil {
367- os.RemoveAll(stage)
367+ _ = os.RemoveAll(stage)
368368 return nil, e
369369 }
370370 if e := os.Rename(stage, u.dir()); e != nil {
371- os.RemoveAll(stage)
371+ _ = os.RemoveAll(stage)
372372 return nil, e
373373 }
374374 if e := syncDir(filepath.Join(s.root, "multipart")); e != nil {
375- os.RemoveAll(u.dir())
375+ _ = os.RemoveAll(u.dir())
376376 return nil, e
377377 }
378378 return u, nil
@@ -396,7 +396,7 @@ func writeMetadata(dir string, m metadata) error {
396396 e = os.Rename(f.Name(), filepath.Join(dir, "metadata"))
397397 }
398398 if e != nil {
399- os.Remove(f.Name())
399+ _ = os.Remove(f.Name())
400400 return e
401401 }
402402 return syncDir(dir)
@@ -412,7 +412,7 @@ func (u *upload) UploadPart(ctx context.Context, n int, r io.Reader, size int64)
412412 if e != nil {
413413 return e
414414 }
415- defer os.Remove(f.Name())
415+ defer func() { _ = os.Remove(f.Name()) }()
416416 count, e := io.Copy(f, ctxReader{ctx, r})
417417 if e == nil && count != size {
418418 e = domain.ErrInvalid
@@ -433,7 +433,7 @@ func (u *upload) Complete(ctx context.Context) (ports.BlobInfo, error) {
433433 return ports.BlobInfo{}, domain.ErrInvalid
434434 }
435435 u.done = true
436- defer os.RemoveAll(u.dir())
436+ defer func() { _ = os.RemoveAll(u.dir()) }()
437437 entries, e := os.ReadDir(u.dir())
438438 if e != nil {
439439 return ports.BlobInfo{}, e
@@ -453,7 +453,7 @@ func (u *upload) Complete(ctx context.Context) (ports.BlobInfo, error) {
453453 var files []*os.File
454454 defer func() {
455455 for _, f := range files {
456- f.Close()
456+ _ = f.Close()
457457 }
458458 }()
459459 for i, n := range names {
@@ -183,7 +183,7 @@ func (s *Store) Put(ctx context.Context, key string, r io.Reader, size int64) (p
183 if e != nil {183 if e != nil {
184 return ports.BlobInfo{}, e184 return ports.BlobInfo{}, e
185 }185 }
186- defer os.Remove(f.Name())186+ defer func() { _ = os.Remove(f.Name()) }()
187 h := sha256.New()187 h := sha256.New()
188 n, e := io.Copy(io.MultiWriter(f, h), ctxReader{ctx, r})188 n, e := io.Copy(io.MultiWriter(f, h), ctxReader{ctx, r})
189 if e == nil && n != size {189 if e == nil && n != size {
@@ -256,7 +256,7 @@ func (s *Store) Open(ctx context.Context, key string, offset, length int64) (io.
256 return nil, info, translate(e)256 return nil, info, translate(e)
257 }257 }
258 if _, e = f.Seek(offset, io.SeekStart); e != nil {258 if _, e = f.Seek(offset, io.SeekStart); e != nil {
259- f.Close()259+ _ = f.Close()
260 return nil, info, e260 return nil, info, e
261 }261 }
262 var r io.Reader = ctxReader{ctx, f}262 var r io.Reader = ctxReader{ctx, f}
@@ -364,15 +364,15 @@ func (s *Store) NewMultipart(ctx context.Context, key string) (ports.MultipartUp
364 return nil, e364 return nil, e
365 }365 }
366 if e := writeMetadata(stage, metadata{key, time.Now().UTC()}); e != nil {366 if e := writeMetadata(stage, metadata{key, time.Now().UTC()}); e != nil {
367- os.RemoveAll(stage)367+ _ = os.RemoveAll(stage)
368 return nil, e368 return nil, e
369 }369 }
370 if e := os.Rename(stage, u.dir()); e != nil {370 if e := os.Rename(stage, u.dir()); e != nil {
371- os.RemoveAll(stage)371+ _ = os.RemoveAll(stage)
372 return nil, e372 return nil, e
373 }373 }
374 if e := syncDir(filepath.Join(s.root, "multipart")); e != nil {374 if e := syncDir(filepath.Join(s.root, "multipart")); e != nil {
375- os.RemoveAll(u.dir())375+ _ = os.RemoveAll(u.dir())
376 return nil, e376 return nil, e
377 }377 }
378 return u, nil378 return u, nil
@@ -396,7 +396,7 @@ func writeMetadata(dir string, m metadata) error {
396 e = os.Rename(f.Name(), filepath.Join(dir, "metadata"))396 e = os.Rename(f.Name(), filepath.Join(dir, "metadata"))
397 }397 }
398 if e != nil {398 if e != nil {
399- os.Remove(f.Name())399+ _ = os.Remove(f.Name())
400 return e400 return e
401 }401 }
402 return syncDir(dir)402 return syncDir(dir)
@@ -412,7 +412,7 @@ func (u *upload) UploadPart(ctx context.Context, n int, r io.Reader, size int64)
412 if e != nil {412 if e != nil {
413 return e413 return e
414 }414 }
415- defer os.Remove(f.Name())415+ defer func() { _ = os.Remove(f.Name()) }()
416 count, e := io.Copy(f, ctxReader{ctx, r})416 count, e := io.Copy(f, ctxReader{ctx, r})
417 if e == nil && count != size {417 if e == nil && count != size {
418 e = domain.ErrInvalid418 e = domain.ErrInvalid
@@ -433,7 +433,7 @@ func (u *upload) Complete(ctx context.Context) (ports.BlobInfo, error) {
433 return ports.BlobInfo{}, domain.ErrInvalid433 return ports.BlobInfo{}, domain.ErrInvalid
434 }434 }
435 u.done = true435 u.done = true
436- defer os.RemoveAll(u.dir())436+ defer func() { _ = os.RemoveAll(u.dir()) }()
437 entries, e := os.ReadDir(u.dir())437 entries, e := os.ReadDir(u.dir())
438 if e != nil {438 if e != nil {
439 return ports.BlobInfo{}, e439 return ports.BlobInfo{}, e
@@ -453,7 +453,7 @@ func (u *upload) Complete(ctx context.Context) (ports.BlobInfo, error) {
453 var files []*os.File453 var files []*os.File
454 defer func() {454 defer func() {
455 for _, f := range files {455 for _, f := range files {
456- f.Close()456+ _ = f.Close()
457 }457 }
458 }()458 }()
459 for i, n := range names {459 for i, n := range names {
M internal/adapters/blobs3/blobs3_test.go +1 -1
@@ -75,7 +75,7 @@ func TestCheckDeniedHeadFallsBack(t *testing.T) {
7575 }
7676 listed = true
7777 w.Header().Set("Content-Type", "application/xml")
78- w.Write([]byte(`<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Name>b</Name><IsTruncated>false</IsTruncated></ListBucketResult>`))
78+ _, _ = w.Write([]byte(`<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Name>b</Name><IsTruncated>false</IsTruncated></ListBucketResult>`))
7979 }))
8080 defer srv.Close()
8181 s, e := blobs3.New(context.Background(), blobs3.Config{Bucket: "b", Prefix: "pfx", Endpoint: srv.URL, Region: "test-region", AccessKeyID: "test", SecretAccessKey: "test-secret", ForcePathStyle: true})
@@ -75,7 +75,7 @@ func TestCheckDeniedHeadFallsBack(t *testing.T) {
75 }75 }
76 listed = true76 listed = true
77 w.Header().Set("Content-Type", "application/xml")77 w.Header().Set("Content-Type", "application/xml")
78- w.Write([]byte(`<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Name>b</Name><IsTruncated>false</IsTruncated></ListBucketResult>`))78+ _, _ = w.Write([]byte(`<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Name>b</Name><IsTruncated>false</IsTruncated></ListBucketResult>`))
79 }))79 }))
80 defer srv.Close()80 defer srv.Close()
81 s, e := blobs3.New(context.Background(), blobs3.Config{Bucket: "b", Prefix: "pfx", Endpoint: srv.URL, Region: "test-region", AccessKeyID: "test", SecretAccessKey: "test-secret", ForcePathStyle: true})81 s, e := blobs3.New(context.Background(), blobs3.Config{Bucket: "b", Prefix: "pfx", Endpoint: srv.URL, Region: "test-region", AccessKeyID: "test", SecretAccessKey: "test-secret", ForcePathStyle: true})
M internal/adapters/blobtest/suite.go +3 -3
@@ -77,7 +77,7 @@ func Run(t *testing.T, newStore func(*testing.T) ports.BlobStore, opts ...Option
7777 require.NoError(t, e)
7878 b, e := io.ReadAll(rc)
7979 require.NoError(t, e)
80- rc.Close()
80+ _ = rc.Close()
8181 require.Equal(t, "new", string(b))
8282 require.NoError(t, s.Delete(ctx, "ci/roundtrip"))
8383 require.NoError(t, s.Delete(ctx, "ci/roundtrip"))
@@ -95,7 +95,7 @@ func Run(t *testing.T, newStore func(*testing.T) ports.BlobStore, opts ...Option
9595 r, _, e := s.Open(ctx, k, 0, -1)
9696 require.NoError(t, e)
9797 b, e := io.ReadAll(r)
98- r.Close()
98+ _ = r.Close()
9999 require.NoError(t, e)
100100 require.Equal(t, k, string(b))
101101 }
@@ -147,7 +147,7 @@ func Run(t *testing.T, newStore func(*testing.T) ports.BlobStore, opts ...Option
147147 r, _, e := s.Open(ctx, "ci/multi", 0, -1)
148148 require.NoError(t, e)
149149 b, e := io.ReadAll(r)
150- r.Close()
150+ _ = r.Close()
151151 require.NoError(t, e)
152152 require.Equal(t, all, b)
153153 })
@@ -77,7 +77,7 @@ func Run(t *testing.T, newStore func(*testing.T) ports.BlobStore, opts ...Option
77 require.NoError(t, e)77 require.NoError(t, e)
78 b, e := io.ReadAll(rc)78 b, e := io.ReadAll(rc)
79 require.NoError(t, e)79 require.NoError(t, e)
80- rc.Close()80+ _ = rc.Close()
81 require.Equal(t, "new", string(b))81 require.Equal(t, "new", string(b))
82 require.NoError(t, s.Delete(ctx, "ci/roundtrip"))82 require.NoError(t, s.Delete(ctx, "ci/roundtrip"))
83 require.NoError(t, s.Delete(ctx, "ci/roundtrip"))83 require.NoError(t, s.Delete(ctx, "ci/roundtrip"))
@@ -95,7 +95,7 @@ func Run(t *testing.T, newStore func(*testing.T) ports.BlobStore, opts ...Option
95 r, _, e := s.Open(ctx, k, 0, -1)95 r, _, e := s.Open(ctx, k, 0, -1)
96 require.NoError(t, e)96 require.NoError(t, e)
97 b, e := io.ReadAll(r)97 b, e := io.ReadAll(r)
98- r.Close()98+ _ = r.Close()
99 require.NoError(t, e)99 require.NoError(t, e)
100 require.Equal(t, k, string(b))100 require.Equal(t, k, string(b))
101 }101 }
@@ -147,7 +147,7 @@ func Run(t *testing.T, newStore func(*testing.T) ports.BlobStore, opts ...Option
147 r, _, e := s.Open(ctx, "ci/multi", 0, -1)147 r, _, e := s.Open(ctx, "ci/multi", 0, -1)
148 require.NoError(t, e)148 require.NoError(t, e)
149 b, e := io.ReadAll(r)149 b, e := io.ReadAll(r)
150- r.Close()150+ _ = r.Close()
151 require.NoError(t, e)151 require.NoError(t, e)
152 require.Equal(t, all, b)152 require.Equal(t, all, b)
153 })153 })
M internal/adapters/kvstore/releases_test.go +1 -1
@@ -106,7 +106,7 @@ func TestReleaseStorage(t *testing.T) {
106106 require.NoError(t, s.Close(ctx))
107107 db, err := kv.Open(ctx, dir, kv.Options{})
108108 require.NoError(t, err)
109- defer db.Close(ctx)
109+ defer func() { _ = db.Close(ctx) }()
110110 for _, prefix := range []string{"rel/", "reltag/", "relid/", "relasset/", "relassets/", "reluse/"} {
111111 for key := range db.Snapshot(ctx).Prefix(ctx, []byte(prefix)) {
112112 t.Errorf("repository deletion left release key %q", key)
@@ -106,7 +106,7 @@ func TestReleaseStorage(t *testing.T) {
106 require.NoError(t, s.Close(ctx))106 require.NoError(t, s.Close(ctx))
107 db, err := kv.Open(ctx, dir, kv.Options{})107 db, err := kv.Open(ctx, dir, kv.Options{})
108 require.NoError(t, err)108 require.NoError(t, err)
109- defer db.Close(ctx)109+ defer func() { _ = db.Close(ctx) }()
110 for _, prefix := range []string{"rel/", "reltag/", "relid/", "relasset/", "relassets/", "reluse/"} {110 for _, prefix := range []string{"rel/", "reltag/", "relid/", "relasset/", "relassets/", "reluse/"} {
111 for key := range db.Snapshot(ctx).Prefix(ctx, []byte(prefix)) {111 for key := range db.Snapshot(ctx).Prefix(ctx, []byte(prefix)) {
112 t.Errorf("repository deletion left release key %q", key)112 t.Errorf("repository deletion left release key %q", key)
M internal/adapters/kvstore/store_test.go +1 -1
@@ -405,7 +405,7 @@ func TestSchema6TokenUpgrade(t *testing.T) {
405405 assert.Equal(t, uint32(kvstore.SchemaVersion), readSchema(t, dir))
406406 db, err := kv.Open(ctx, dir, kv.Options{})
407407 require.NoError(t, err)
408- defer db.Close(ctx)
408+ defer func() { _ = db.Close(ctx) }()
409409 for _, id := range []string{"full", "partial", "missing-review", "repo", "branch"} {
410410 item, ok := db.Get(ctx, []byte("token/"+id))
411411 require.True(t, ok)
@@ -405,7 +405,7 @@ func TestSchema6TokenUpgrade(t *testing.T) {
405 assert.Equal(t, uint32(kvstore.SchemaVersion), readSchema(t, dir))405 assert.Equal(t, uint32(kvstore.SchemaVersion), readSchema(t, dir))
406 db, err := kv.Open(ctx, dir, kv.Options{})406 db, err := kv.Open(ctx, dir, kv.Options{})
407 require.NoError(t, err)407 require.NoError(t, err)
408- defer db.Close(ctx)408+ defer func() { _ = db.Close(ctx) }()
409 for _, id := range []string{"full", "partial", "missing-review", "repo", "branch"} {409 for _, id := range []string{"full", "partial", "missing-review", "repo", "branch"} {
410 item, ok := db.Get(ctx, []byte("token/"+id))410 item, ok := db.Get(ctx, []byte("token/"+id))
411 require.True(t, ok)411 require.True(t, ok)
M internal/adapters/rpc/release_test.go +5 -5
@@ -256,7 +256,7 @@ func TestReleaseRPCDownload(t *testing.T) {
256256 }).Once()
257257 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(req))
258258 require.NoError(t, err)
259- defer stream.Close()
259+ defer func() { _ = stream.Close() }()
260260 require.True(t, stream.Receive())
261261 assert.True(t, proto.Equal(assetToPB(a), stream.Msg().Asset))
262262 assert.Empty(t, stream.Msg().Chunk)
@@ -285,7 +285,7 @@ func TestReleaseRPCErrors(t *testing.T) {
285285 rel.EXPECT().DownloadAsset(mock.Anything, domain.Anonymous(), mustRepoName(t, "demo"), ports.AssetRef{ID: 9}, int64(0), int64(-1), mock.Anything).Return(tt.err).Once()
286286 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))
287287 if err == nil {
288- defer stream.Close()
288+ defer func() { _ = stream.Close() }()
289289 assert.False(t, stream.Receive())
290290 err = stream.Err()
291291 }
@@ -395,7 +395,7 @@ func TestReleaseRPCDownloadFullChunk(t *testing.T) {
395395 }).Once()
396396 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))
397397 require.NoError(t, err)
398- defer stream.Close()
398+ defer func() { _ = stream.Close() }()
399399 require.True(t, stream.Receive())
400400 require.NotNil(t, stream.Msg().Asset)
401401 require.True(t, stream.Receive())
@@ -414,7 +414,7 @@ func TestReleaseRPCRejectsInvalidMasksAndSelectors(t *testing.T) {
414414 requireCode(t, connect.CodeInvalidArgument, err)
415415 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_Latest{Latest: &pb.ReleaseAssetLatest{Name: "a"}}}))
416416 if err == nil {
417- defer stream.Close()
417+ defer func() { _ = stream.Close() }()
418418 assert.False(t, stream.Receive())
419419 err = stream.Err()
420420 }
@@ -464,7 +464,7 @@ func TestReleaseRPCDownloadZeroByteAsset(t *testing.T) {
464464 }).Once()
465465 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))
466466 require.NoError(t, err)
467- defer stream.Close()
467+ defer func() { _ = stream.Close() }()
468468 require.True(t, stream.Receive())
469469 assert.True(t, proto.Equal(assetToPB(a), stream.Msg().Asset))
470470 assert.False(t, stream.Receive())
@@ -256,7 +256,7 @@ func TestReleaseRPCDownload(t *testing.T) {
256 }).Once()256 }).Once()
257 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(req))257 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(req))
258 require.NoError(t, err)258 require.NoError(t, err)
259- defer stream.Close()259+ defer func() { _ = stream.Close() }()
260 require.True(t, stream.Receive())260 require.True(t, stream.Receive())
261 assert.True(t, proto.Equal(assetToPB(a), stream.Msg().Asset))261 assert.True(t, proto.Equal(assetToPB(a), stream.Msg().Asset))
262 assert.Empty(t, stream.Msg().Chunk)262 assert.Empty(t, stream.Msg().Chunk)
@@ -285,7 +285,7 @@ func TestReleaseRPCErrors(t *testing.T) {
285 rel.EXPECT().DownloadAsset(mock.Anything, domain.Anonymous(), mustRepoName(t, "demo"), ports.AssetRef{ID: 9}, int64(0), int64(-1), mock.Anything).Return(tt.err).Once()285 rel.EXPECT().DownloadAsset(mock.Anything, domain.Anonymous(), mustRepoName(t, "demo"), ports.AssetRef{ID: 9}, int64(0), int64(-1), mock.Anything).Return(tt.err).Once()
286 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))286 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))
287 if err == nil {287 if err == nil {
288- defer stream.Close()288+ defer func() { _ = stream.Close() }()
289 assert.False(t, stream.Receive())289 assert.False(t, stream.Receive())
290 err = stream.Err()290 err = stream.Err()
291 }291 }
@@ -395,7 +395,7 @@ func TestReleaseRPCDownloadFullChunk(t *testing.T) {
395 }).Once()395 }).Once()
396 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))396 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))
397 require.NoError(t, err)397 require.NoError(t, err)
398- defer stream.Close()398+ defer func() { _ = stream.Close() }()
399 require.True(t, stream.Receive())399 require.True(t, stream.Receive())
400 require.NotNil(t, stream.Msg().Asset)400 require.NotNil(t, stream.Msg().Asset)
401 require.True(t, stream.Receive())401 require.True(t, stream.Receive())
@@ -414,7 +414,7 @@ func TestReleaseRPCRejectsInvalidMasksAndSelectors(t *testing.T) {
414 requireCode(t, connect.CodeInvalidArgument, err)414 requireCode(t, connect.CodeInvalidArgument, err)
415 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_Latest{Latest: &pb.ReleaseAssetLatest{Name: "a"}}}))415 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_Latest{Latest: &pb.ReleaseAssetLatest{Name: "a"}}}))
416 if err == nil {416 if err == nil {
417- defer stream.Close()417+ defer func() { _ = stream.Close() }()
418 assert.False(t, stream.Receive())418 assert.False(t, stream.Receive())
419 err = stream.Err()419 err = stream.Err()
420 }420 }
@@ -464,7 +464,7 @@ func TestReleaseRPCDownloadZeroByteAsset(t *testing.T) {
464 }).Once()464 }).Once()
465 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))465 stream, err := c.DownloadReleaseAsset(context.Background(), connect.NewRequest(&pb.DownloadReleaseAssetRequest{Repo: "demo", Selector: &pb.DownloadReleaseAssetRequest_AssetId{AssetId: 9}}))
466 require.NoError(t, err)466 require.NoError(t, err)
467- defer stream.Close()467+ defer func() { _ = stream.Close() }()
468 require.True(t, stream.Receive())468 require.True(t, stream.Receive())
469 assert.True(t, proto.Equal(assetToPB(a), stream.Msg().Asset))469 assert.True(t, proto.Equal(assetToPB(a), stream.Msg().Asset))
470 assert.False(t, stream.Receive())470 assert.False(t, stream.Receive())
M internal/app/cli_release.go +1 -1
@@ -589,7 +589,7 @@ func downloadReleaseAsset(ctx context.Context, c *client.Client, repo string, a
589589 return ctx.Err()
590590 }
591591 code := connect.CodeOf(err)
592- if attempt == 1 || !(code == connect.CodeUnavailable || code == connect.CodeInternal || errors.Is(err, io.ErrUnexpectedEOF)) {
592+ if attempt == 1 || (code != connect.CodeUnavailable && code != connect.CodeInternal && !errors.Is(err, io.ErrUnexpectedEOF)) {
593593 return c.Describe(err)
594594 }
595595 }
@@ -589,7 +589,7 @@ func downloadReleaseAsset(ctx context.Context, c *client.Client, repo string, a
589 return ctx.Err()589 return ctx.Err()
590 }590 }
591 code := connect.CodeOf(err)591 code := connect.CodeOf(err)
592- if attempt == 1 || !(code == connect.CodeUnavailable || code == connect.CodeInternal || errors.Is(err, io.ErrUnexpectedEOF)) {592+ if attempt == 1 || (code != connect.CodeUnavailable && code != connect.CodeInternal && !errors.Is(err, io.ErrUnexpectedEOF)) {
593 return c.Describe(err)593 return c.Describe(err)
594 }594 }
595 }595 }
M internal/app/release_e2e_test.go +2 -2
@@ -76,7 +76,7 @@ func TestReleaseBlobForge(t *testing.T) {
7676 require.NoError(t, err)
7777 body, err := io.ReadAll(res.Body)
7878 require.NoError(t, err)
79- res.Body.Close()
79+ _ = res.Body.Close()
8080 assert.Equal(t, 206, res.StatusCode)
8181 assert.Equal(t, "ayl", string(body))
8282 assert.Empty(t, res.Header.Get("Location"))
@@ -84,7 +84,7 @@ func TestReleaseBlobForge(t *testing.T) {
8484 require.NoError(t, err)
8585 var obj map[string]any
8686 require.NoError(t, json.NewDecoder(res.Body).Decode(&obj))
87- res.Body.Close()
87+ _ = res.Body.Close()
8888 assert.Equal(t, 200, res.StatusCode)
8989 assert.Contains(t, obj["upload_url"], "http://example.test/-/github/api/uploads/")
9090 // New artifacts use the same production backend, not a test-local blob store.
@@ -76,7 +76,7 @@ func TestReleaseBlobForge(t *testing.T) {
76 require.NoError(t, err)76 require.NoError(t, err)
77 body, err := io.ReadAll(res.Body)77 body, err := io.ReadAll(res.Body)
78 require.NoError(t, err)78 require.NoError(t, err)
79- res.Body.Close()79+ _ = res.Body.Close()
80 assert.Equal(t, 206, res.StatusCode)80 assert.Equal(t, 206, res.StatusCode)
81 assert.Equal(t, "ayl", string(body))81 assert.Equal(t, "ayl", string(body))
82 assert.Empty(t, res.Header.Get("Location"))82 assert.Empty(t, res.Header.Get("Location"))
@@ -84,7 +84,7 @@ func TestReleaseBlobForge(t *testing.T) {
84 require.NoError(t, err)84 require.NoError(t, err)
85 var obj map[string]any85 var obj map[string]any
86 require.NoError(t, json.NewDecoder(res.Body).Decode(&obj))86 require.NoError(t, json.NewDecoder(res.Body).Decode(&obj))
87- res.Body.Close()87+ _ = res.Body.Close()
88 assert.Equal(t, 200, res.StatusCode)88 assert.Equal(t, 200, res.StatusCode)
89 assert.Contains(t, obj["upload_url"], "http://example.test/-/github/api/uploads/")89 assert.Contains(t, obj["upload_url"], "http://example.test/-/github/api/uploads/")
90 // New artifacts use the same production backend, not a test-local blob store.90 // New artifacts use the same production backend, not a test-local blob store.
M internal/app/web_release_test.go +1 -1
@@ -44,7 +44,7 @@ func TestWebRelease(t *testing.T) {
4444 }
4545 res, err := ts.Client().Do(req)
4646 require.NoError(t, err)
47- defer res.Body.Close()
47+ defer func() { _ = res.Body.Close() }()
4848 body, err := io.ReadAll(res.Body)
4949 require.NoError(t, err)
5050 return res.StatusCode, res.Header, string(body)
@@ -44,7 +44,7 @@ func TestWebRelease(t *testing.T) {
44 }44 }
45 res, err := ts.Client().Do(req)45 res, err := ts.Client().Do(req)
46 require.NoError(t, err)46 require.NoError(t, err)
47- defer res.Body.Close()47+ defer func() { _ = res.Body.Close() }()
48 body, err := io.ReadAll(res.Body)48 body, err := io.ReadAll(res.Body)
49 require.NoError(t, err)49 require.NoError(t, err)
50 return res.StatusCode, res.Header, string(body)50 return res.StatusCode, res.Header, string(body)
M internal/usecase/releases_assets.go +3 -3
@@ -66,7 +66,7 @@ func (r *Releases) UploadAsset(ctx context.Context, p domain.Principal, name dom
6666 if old.Name != a.Name {
6767 continue
6868 }
69- if !(old.State == domain.ReleaseAssetUploading && r.clock.Now().Sub(old.UpdatedAt) > 60*time.Second) && !(old.State == domain.ReleaseAssetUploaded && params.Replace) {
69+ if (old.State != domain.ReleaseAssetUploading || r.clock.Now().Sub(old.UpdatedAt) <= 60*time.Second) && (old.State != domain.ReleaseAssetUploaded || !params.Replace) {
7070 return fmt.Errorf("%w: an asset named %q already exists", domain.ErrAlreadyExists, a.Name)
7171 }
7272 replaced = append(replaced, old)
@@ -199,7 +199,7 @@ func validReleaseDigest(s string) bool {
199199 return false
200200 }
201201 for _, c := range s[7:] {
202- if !(c >= '0' && c <= '9' || c >= 'a' && c <= 'f') {
202+ if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
203203 return false
204204 }
205205 }
@@ -407,7 +407,7 @@ func (r *Releases) DownloadAsset(ctx context.Context, p domain.Principal, repo d
407407 }
408408 return err
409409 }
410- defer body.Close()
410+ defer func() { _ = body.Close() }()
411411 if err = send(ports.AssetChunk{Asset: &a}); err != nil {
412412 return err
413413 }
@@ -66,7 +66,7 @@ func (r *Releases) UploadAsset(ctx context.Context, p domain.Principal, name dom
66 if old.Name != a.Name {66 if old.Name != a.Name {
67 continue67 continue
68 }68 }
69- if !(old.State == domain.ReleaseAssetUploading && r.clock.Now().Sub(old.UpdatedAt) > 60*time.Second) && !(old.State == domain.ReleaseAssetUploaded && params.Replace) {69+ if (old.State != domain.ReleaseAssetUploading || r.clock.Now().Sub(old.UpdatedAt) <= 60*time.Second) && (old.State != domain.ReleaseAssetUploaded || !params.Replace) {
70 return fmt.Errorf("%w: an asset named %q already exists", domain.ErrAlreadyExists, a.Name)70 return fmt.Errorf("%w: an asset named %q already exists", domain.ErrAlreadyExists, a.Name)
71 }71 }
72 replaced = append(replaced, old)72 replaced = append(replaced, old)
@@ -199,7 +199,7 @@ func validReleaseDigest(s string) bool {
199 return false199 return false
200 }200 }
201 for _, c := range s[7:] {201 for _, c := range s[7:] {
202- if !(c >= '0' && c <= '9' || c >= 'a' && c <= 'f') {202+ if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
203 return false203 return false
204 }204 }
205 }205 }
@@ -407,7 +407,7 @@ func (r *Releases) DownloadAsset(ctx context.Context, p domain.Principal, repo d
407 }407 }
408 return err408 return err
409 }409 }
410- defer body.Close()410+ defer func() { _ = body.Close() }()
411 if err = send(ports.AssetChunk{Asset: &a}); err != nil {411 if err = send(ports.AssetChunk{Asset: &a}); err != nil {
412 return err412 return err
413 }413 }
M internal/usecase/releases_github_test.go +1 -1
@@ -307,7 +307,7 @@ func TestGitHubReleaseHTTPWorkflow(t *testing.T) {
307307 }
308308 resp, err := srv.Client().Do(req)
309309 require.NoError(t, err)
310- defer resp.Body.Close()
310+ defer func() { _ = resp.Body.Close() }()
311311 b, err := io.ReadAll(resp.Body)
312312 require.NoError(t, err)
313313 return resp, string(b)
@@ -307,7 +307,7 @@ func TestGitHubReleaseHTTPWorkflow(t *testing.T) {
307 }307 }
308 resp, err := srv.Client().Do(req)308 resp, err := srv.Client().Do(req)
309 require.NoError(t, err)309 require.NoError(t, err)
310- defer resp.Body.Close()310+ defer func() { _ = resp.Body.Close() }()
311 b, err := io.ReadAll(resp.Body)311 b, err := io.ReadAll(resp.Body)
312 require.NoError(t, err)312 require.NoError(t, err)
313 return resp, string(b)313 return resp, string(b)
M internal/usecase/releases_sweep.go +3 -2
@@ -29,9 +29,10 @@ func (r *Releases) Sweep(ctx context.Context) {
2929 for _, a := range all {
3030 seen[a.ID] = true
3131 remove := false
32- if a.State == domain.ReleaseAssetUploading {
32+ switch a.State {
33+ case domain.ReleaseAssetUploading:
3334 remove = now.Sub(a.UpdatedAt) > domain.ReleaseAssetPendingMax
34- } else if a.State == domain.ReleaseAssetUploaded {
35+ case domain.ReleaseAssetUploaded:
3536 _, err := r.blobs.Stat(ctx, a.BlobKey())
3637 switch {
3738 case errors.Is(err, domain.ErrNotFound):
@@ -29,9 +29,10 @@ func (r *Releases) Sweep(ctx context.Context) {
29 for _, a := range all {29 for _, a := range all {
30 seen[a.ID] = true30 seen[a.ID] = true
31 remove := false31 remove := false
32- if a.State == domain.ReleaseAssetUploading {32+ switch a.State {
33+ case domain.ReleaseAssetUploading:
33 remove = now.Sub(a.UpdatedAt) > domain.ReleaseAssetPendingMax34 remove = now.Sub(a.UpdatedAt) > domain.ReleaseAssetPendingMax
34- } else if a.State == domain.ReleaseAssetUploaded {35+ case domain.ReleaseAssetUploaded:
35 _, err := r.blobs.Stat(ctx, a.BlobKey())36 _, err := r.blobs.Stat(ctx, a.BlobKey())
36 switch {37 switch {
37 case errors.Is(err, domain.ErrNotFound):38 case errors.Is(err, domain.ErrNotFound):

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 42

↑↓ moveenter openesc close