chore: update golangci-lint to v2.12.2 with canonical config
All checks were successful
check / check (push) Successful in 2m3s

Replace .golangci.yml with the canonical v2-schema config
(default: all minus six disabled linters, lll 88, tests included)
and bump every golangci-lint pin to v2.12.2:

- Dockerfile: golangci/golangci-lint:v2.12.2-alpine (hash-pinned)
- script/bootstrap: GOLANGCI_LINT_VERSION 2.12.2 with new
  linux-amd64/arm64 release-archive sha256 pins

Fix all 747 findings the stricter config surfaces, with no behavior
changes: t.Parallel() throughout the test suite, static sentinel
errors and errors.Is comparisons, checked error returns, context
propagation (contextcheck/noctx), 88-column wrapping, extracted
constants and helpers for goconst/dupl/funlen/cyclop, exhaustive
switch cases replicating existing defaults, and white-box test files
renamed to *_internal_test.go for testpackage. Three
nolint:tagliatelle directives preserve the existing snake_case JSON
wire and on-disk metadata formats.
This commit is contained in:
2026-08-07 17:10:27 +00:00
parent 5d0b5f864e
commit 23506df609
55 changed files with 2584 additions and 1863 deletions

View File

@@ -13,7 +13,9 @@ import (
)
// vipsOnce ensures vips is initialized exactly once.
var vipsOnce sync.Once //nolint:gochecknoglobals // package-level sync.Once for one-time vips init
//
//nolint:gochecknoglobals // package-level sync.Once for one-time vips init
var vipsOnce sync.Once
// initVips initializes libvips with quiet logging.
func initVips() {
@@ -96,10 +98,12 @@ const DefaultMaxInputBytes = 50 << 20
// ErrInputTooLarge is returned when input image dimensions exceed MaxInputDimension.
var ErrInputTooLarge = errors.New("input image dimensions exceed maximum")
// ErrInputDataTooLarge is returned when the raw input data exceeds the configured byte limit.
// ErrInputDataTooLarge is returned when the raw input data exceeds the
// configured byte limit.
var ErrInputDataTooLarge = errors.New("input data exceeds maximum allowed size")
// ErrUnsupportedOutputFormat is returned when the requested output format is not supported.
// ErrUnsupportedOutputFormat is returned when the requested output format is
// not supported.
var ErrUnsupportedOutputFormat = errors.New("unsupported output format")
// ImageProcessor implements image transformation using libvips via govips.
@@ -170,25 +174,12 @@ func (p *ImageProcessor) Process(
}
// Determine target dimensions
targetWidth := req.Size.Width
targetHeight := req.Size.Height
// Handle dimension calculation
if targetWidth == 0 && targetHeight == 0 {
// Both are 0: keep original size
targetWidth = origWidth
targetHeight = origHeight
} else if targetWidth == 0 {
// Only height specified: calculate width proportionally
targetWidth = origWidth * targetHeight / origHeight
} else if targetHeight == 0 {
// Only width specified: calculate height proportionally
targetHeight = origHeight * targetWidth / origWidth
}
targetWidth, targetHeight := targetDimensions(req.Size, origWidth, origHeight)
// Resize if needed
if targetWidth != origWidth || targetHeight != origHeight {
if err := p.resize(img, targetWidth, targetHeight, req.FitMode); err != nil {
err := p.resize(img, targetWidth, targetHeight, req.FitMode)
if err != nil {
return nil, fmt.Errorf("failed to resize: %w", err)
}
}
@@ -217,14 +208,42 @@ func (p *ImageProcessor) Process(
}, nil
}
// targetDimensions calculates the output dimensions for a requested size,
// scaling proportionally when only one dimension is given and keeping the
// original dimensions when both are zero.
func targetDimensions(size Size, origWidth, origHeight int) (int, int) {
switch {
case size.Width == 0 && size.Height == 0:
// Both are 0: keep original size
return origWidth, origHeight
case size.Width == 0:
// Only height specified: calculate width proportionally
return origWidth * size.Height / origHeight, size.Height
case size.Height == 0:
// Only width specified: calculate height proportionally
return size.Width, origHeight * size.Width / origWidth
default:
return size.Width, size.Height
}
}
// MIME types for the supported image formats.
const (
mimeJPEG = "image/jpeg"
mimePNG = "image/png"
mimeGIF = "image/gif"
mimeWebP = "image/webp"
mimeAVIF = "image/avif"
)
// SupportedInputFormats returns MIME types this processor can read.
func (p *ImageProcessor) SupportedInputFormats() []string {
return []string{
"image/jpeg",
"image/png",
"image/gif",
"image/webp",
"image/avif",
mimeJPEG,
mimePNG,
mimeGIF,
mimeWebP,
mimeAVIF,
}
}
@@ -243,15 +262,17 @@ func (p *ImageProcessor) SupportedOutputFormats() []Format {
func FormatToMIME(format Format) string {
switch format {
case FormatJPEG:
return "image/jpeg"
return mimeJPEG
case FormatPNG:
return "image/png"
return mimePNG
case FormatWebP:
return "image/webp"
return mimeWebP
case FormatGIF:
return "image/gif"
return mimeGIF
case FormatAVIF:
return "image/avif"
return mimeAVIF
case FormatOriginal:
return "application/octet-stream"
default:
return "application/octet-stream"
}
@@ -270,14 +291,20 @@ func (p *ImageProcessor) detectFormat(img *vips.ImageRef) string {
case vips.ImageTypeWEBP:
return "webp"
case vips.ImageTypeAVIF, vips.ImageTypeHEIF:
return "avif"
return string(FormatAVIF)
case vips.ImageTypeUnknown, vips.ImageTypeMagick, vips.ImageTypePDF,
vips.ImageTypeSVG, vips.ImageTypeTIFF, vips.ImageTypeBMP,
vips.ImageTypeJP2K, vips.ImageTypeJXL:
return "unknown"
default:
return "unknown"
}
}
// resize resizes the image according to the fit mode.
func (p *ImageProcessor) resize(img *vips.ImageRef, width, height int, fit FitMode) error {
func (p *ImageProcessor) resize(
img *vips.ImageRef, width, height int, fit FitMode,
) error {
switch fit {
case FitCover, "":
// Resize and crop to fill exact dimensions (default)
@@ -303,6 +330,7 @@ func (p *ImageProcessor) resize(img *vips.ImageRef, width, height int, fit FitMo
if img.Width() <= width && img.Height() <= height {
return nil // Already fits
}
imgW, imgH := img.Width(), img.Height()
scaleW := float64(width) / float64(imgW)
scaleH := float64(height) / float64(imgH)
@@ -331,7 +359,9 @@ func (p *ImageProcessor) resize(img *vips.ImageRef, width, height int, fit FitMo
const defaultQuality = 85
// encode encodes an image to the specified format.
func (p *ImageProcessor) encode(img *vips.ImageRef, format Format, quality int) ([]byte, error) {
func (p *ImageProcessor) encode(
img *vips.ImageRef, format Format, quality int,
) ([]byte, error) {
if quality <= 0 {
quality = defaultQuality
}
@@ -367,8 +397,11 @@ func (p *ImageProcessor) encode(img *vips.ImageRef, format Format, quality int)
Quality: quality,
}
case FormatOriginal:
return nil, fmt.Errorf("%w: %s", ErrUnsupportedOutputFormat, format)
default:
return nil, fmt.Errorf("unsupported output format: %s", format)
return nil, fmt.Errorf("%w: %s", ErrUnsupportedOutputFormat, format)
}
output, _, err := img.Export(&params)
@@ -390,7 +423,7 @@ func (p *ImageProcessor) formatFromString(format string) Format {
return FormatGIF
case "webp":
return FormatWebP
case "avif":
case string(FormatAVIF):
return FormatAVIF
default:
return FormatJPEG