Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions .github/actions/setup-go-toolchain/action.yml

This file was deleted.

74 changes: 47 additions & 27 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
# Define a matrix strategy to test against multiple Go versions
strategy:
matrix:
go-version: ['1.26','1.25', '1.24']
go-version: ['1.27','1.26']
# Continue with other jobs if one version fails
fail-fast: false

Expand Down Expand Up @@ -135,11 +135,16 @@ jobs:
go-version: ${{ matrix.go-version }}
id: Go

# go.work pins a newer Go than the older matrix versions install, and a
# plain GOTOOLCHAIN=auto resolves that to a read-only toolchain module.
# See the action for why that breaks coverage builds.
- name: Allow Go toolchain auto-upgrade
uses: ./.github/actions/setup-go-toolchain
# Keep this leg on the Go that setup-go installed. The go command will happily
# upgrade itself to satisfy a newer go directive, and when it does every leg of
# the matrix ends up testing the same toolchain while still reporting three.
# go.work is at the minimum supported version so no upgrade is needed; this pin
# is what stops one from being introduced unnoticed.
- name: Pin the toolchain to this matrix version
shell: bash
run: |
echo "GOTOOLCHAIN=local" >> "$GITHUB_ENV"
go version

- name: Get dependencies
run: |
Expand Down Expand Up @@ -226,9 +231,9 @@ jobs:
S3_REQUIRE_MINIO: "true"
run: go test -v ./...

# Upload coverage report for the 1.24 Go version only
# Upload coverage report for the lowest matrix Go version only
- name: Upload Test Coverage
if: ${{ matrix.go-version == '1.24'}}
if: ${{ matrix.go-version == '1.26'}}
uses: actions/upload-artifact@v7
with:
name: Example-Test-Report
Expand All @@ -241,7 +246,7 @@ jobs:
timeout-minutes: 30
strategy:
matrix:
go-version: ['1.26','1.25', '1.24']
go-version: ['1.27','1.26','1.25']
fail-fast: false

steps:
Expand All @@ -256,11 +261,21 @@ jobs:
go-version: ${{ matrix.go-version }}
id: Go

# go.work pins a newer Go than the older matrix versions install, and a
# plain GOTOOLCHAIN=auto resolves that to a read-only toolchain module.
# See the action for why that breaks coverage builds.
- name: Allow Go toolchain auto-upgrade
uses: ./.github/actions/setup-go-toolchain
# Keep this leg on the Go that setup-go installed. The go command will happily
# upgrade itself to satisfy a newer go directive, and when it does every leg of
# the matrix ends up testing the same toolchain while still reporting three.
# go.work is at the minimum supported version so no upgrade is needed; this pin
# is what stops one from being introduced unnoticed.
- name: Pin the toolchain to this matrix version
shell: bash
run: |
echo "GOTOOLCHAIN=local" >> "$GITHUB_ENV"
# The workspace pulls in the examples and datasource submodules, which
# require published gofr.dev releases built against go 1.26. The root
# module itself does not, so testing it outside the workspace is what
# lets the 1.25 leg exist at all.
echo "GOWORK=off" >> "$GITHUB_ENV"
go version

- name: Get dependencies
run: |
Expand Down Expand Up @@ -314,9 +329,9 @@ jobs:
# Show coverage summary
go tool cover -func profile.cov

# Upload coverage report for the 1.24 Go version only
# Upload coverage report for the lowest matrix Go version only
- name: Upload Test Coverage
if: ${{ matrix.go-version == '1.24'}}
if: ${{ matrix.go-version == '1.25'}}
uses: actions/upload-artifact@v7
with:
name: PKG-Coverage-Report
Expand Down Expand Up @@ -368,7 +383,7 @@ jobs:
timeout-minutes: 30
strategy:
matrix:
go-version: ['1.26','1.25', '1.24']
go-version: ['1.27','1.26']
fail-fast: false

steps:
Expand All @@ -383,11 +398,16 @@ jobs:
go-version: ${{ matrix.go-version }}
id: Go

# go.work pins a newer Go than the older matrix versions install, and a
# plain GOTOOLCHAIN=auto resolves that to a read-only toolchain module.
# See the action for why that breaks coverage builds.
- name: Allow Go toolchain auto-upgrade
uses: ./.github/actions/setup-go-toolchain
# Keep this leg on the Go that setup-go installed. The go command will happily
# upgrade itself to satisfy a newer go directive, and when it does every leg of
# the matrix ends up testing the same toolchain while still reporting three.
# go.work is at the minimum supported version so no upgrade is needed; this pin
# is what stops one from being introduced unnoticed.
- name: Pin the toolchain to this matrix version
shell: bash
run: |
echo "GOTOOLCHAIN=local" >> "$GITHUB_ENV"
go version

# Find all submodules (directories with go.mod files) in the pkg directory
- name: Detect Submodules
Expand Down Expand Up @@ -530,7 +550,7 @@ jobs:
- name: Set up Go environment
uses: actions/setup-go@v7
with:
go-version: '1.26'
go-version: '1.27'
cache: false

- name: Get dependencies
Expand Down Expand Up @@ -564,7 +584,7 @@ jobs:
- name: Lint Root Module
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: v2.12.2
version: v2.13.2
only-new-issues: true
args: --timeout=5m

Expand Down Expand Up @@ -652,7 +672,7 @@ jobs:
- name: Set up Go environment
uses: actions/setup-go@v7
with:
go-version: '1.26'
go-version: '1.27'
cache: false

- name: Download dependencies for ${{ matrix.module }}
Expand All @@ -663,7 +683,7 @@ jobs:
- name: Lint ${{ matrix.module }}
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: v2.12.2
version: v2.13.2
working-directory: ${{ matrix.module }}
only-new-issues: true
args: --timeout=9m
Expand All @@ -680,7 +700,7 @@ jobs:
- name: Set up Go environment
uses: actions/setup-go@v7
with:
go-version: 1.26
go-version: 1.27

# Check file naming conventions using ls-lint
- name: Check for file names errors
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir -p /go/src/gofr.dev
WORKDIR /go/src/gofr.dev
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ GoFr is designed to **simplify microservice development**, with a key focus on *
## 🚀 **Getting Started**

### **Prerequisites**
- GoFr requires **[Go](https://go.dev/)** version **[1.24](https://go.dev/doc/devel/release#go1.24.0)** or above.
- GoFr requires **[Go](https://go.dev/)** version **[1.25](https://go.dev/doc/devel/release#go1.25.0)** or above. The optional datasource modules (`gofr.dev/pkg/gofr/datasource/...`) require **1.26**.

### **Installation**
To get started with GoFr, add the following import to your code and use Go’s module support to automatically fetch dependencies:
Expand Down
2 changes: 1 addition & 1 deletion docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ when working on a GoFr project. It points at the specific docs you'll
actually need rather than inlining everything.

GoFr is an opinionated Go framework for microservices. Apache 2.0.
Requires Go 1.25+. Repo: <https://github.com/gofr-dev/gofr>.
Requires Go 1.25+ (datasource submodules: 1.26+). Repo: <https://github.com/gofr-dev/gofr>.

## Core rules an assistant must know

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/cicd-recipes/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.25' # gofr.dev requires Go >= 1.25 (per its go.mod). Alternatively use `go-version-file: go.mod` to auto-track.
go-version: '1.27' # gofr.dev requires Go >= 1.25 (per its go.mod); 1.27 is simply the newest tested. Alternatively use `go-version-file: go.mod` to auto-track.
cache: true # caches modules + build cache automatically
- run: go vet ./...
- run: go test -race -coverprofile=cover.out ./...
Expand Down
4 changes: 2 additions & 2 deletions docs/guides/dockerizing-gofr-services/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ nextjs:
Two production-ready ways to ship GoFr in a container: a multi-stage build that compiles a static, CGO-disabled binary inside the image, or a copy-binary variant that lifts a CI-built binary into a minimal runtime. Both target `gcr.io/distroless/static-debian12:nonroot`, expose `HTTP_PORT` (8000) and `METRICS_PORT` (2121), read configuration from env vars, and rely on Kubernetes liveness/readiness probes (the `/.well-known/alive` and `/.well-known/health` endpoints GoFr registers) — Dockerfile `HEALTHCHECK` does not work cleanly on distroless.
{% /answer %}

{% howto name="Containerize a GoFr service (multi-stage)" description="Build a small, secure container image for a GoFr binary using a multi-stage Go build." steps=[{"name": "Add a multi-stage Dockerfile", "text": "Use a golang:1.25-alpine builder stage to compile a static binary, then copy it into a gcr.io/distroless/static-debian12:nonroot runtime stage."}, {"name": "Cache module downloads", "text": "COPY go.mod and go.sum first and run go mod download before copying source — combined with a BuildKit cache mount, Docker reuses module downloads across builds."}, {"name": "Compile a static binary", "text": "Set CGO_ENABLED=0 with -trimpath and use -ldflags to embed version/commit, so the runtime image needs no libc and stays minimal."}, {"name": "Run as non-root", "text": "distroless/static-debian12:nonroot already provides UID 65532; set USER nonroot:nonroot to use it."}, {"name": "Probe over HTTP from outside the container", "text": "distroless/static has no shell or wget/curl, so Dockerfile HEALTHCHECK is impractical. On Kubernetes, use livenessProbe/readinessProbe with httpGet on /.well-known/alive and /.well-known/health."}, {"name": "Build and tag", "text": "docker build with a short-SHA tag plus a semver alias so you can roll back by digest."}] /%}
{% howto name="Containerize a GoFr service (multi-stage)" description="Build a small, secure container image for a GoFr binary using a multi-stage Go build." steps=[{"name": "Add a multi-stage Dockerfile", "text": "Use a golang:1.27-alpine builder stage to compile a static binary, then copy it into a gcr.io/distroless/static-debian12:nonroot runtime stage."}, {"name": "Cache module downloads", "text": "COPY go.mod and go.sum first and run go mod download before copying source — combined with a BuildKit cache mount, Docker reuses module downloads across builds."}, {"name": "Compile a static binary", "text": "Set CGO_ENABLED=0 with -trimpath and use -ldflags to embed version/commit, so the runtime image needs no libc and stays minimal."}, {"name": "Run as non-root", "text": "distroless/static-debian12:nonroot already provides UID 65532; set USER nonroot:nonroot to use it."}, {"name": "Probe over HTTP from outside the container", "text": "distroless/static has no shell or wget/curl, so Dockerfile HEALTHCHECK is impractical. On Kubernetes, use livenessProbe/readinessProbe with httpGet on /.well-known/alive and /.well-known/health."}, {"name": "Build and tag", "text": "docker build with a short-SHA tag plus a semver alias so you can roll back by digest."}] /%}

## When to use this guide

Expand Down Expand Up @@ -54,7 +54,7 @@ Save this as `Dockerfile` at the repo root:
```dockerfile
# syntax=docker/dockerfile:1.7

ARG GO_VERSION=1.25
ARG GO_VERSION=1.27
ARG APP_VERSION=dev
ARG GIT_COMMIT=unknown

Expand Down
2 changes: 1 addition & 1 deletion docs/quick-start/introduction/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ GoFr is an opinionated Go framework for production microservices. It bundles HTT

## Prerequisites

- Go 1.25 or above. Check with `go version`.
- Go 1.27 or above. Check with `go version`.
- Familiarity with Go syntax — the {% new-tab-link title="Golang Tour" href="https://tour.golang.org/" /%} is a good 30-minute primer if you're new.

## Write your first GoFr API
Expand Down
2 changes: 1 addition & 1 deletion docs/references/gofrcli/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Managing repetitive tasks and maintaining consistency across large-scale applica

## Prerequisites

- Go 1.25 or above. To check Go version use the following command:
- Go 1.27 or above. To check Go version use the following command:
```bash
go version
```
Expand Down
2 changes: 1 addition & 1 deletion examples/http-server-using-redis/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-add-filestore/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ require (
github.com/graphql-go/graphql v0.8.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
github.com/jlaffaye/ftp v0.2.1 // indirect
github.com/jlaffaye/ftp v0.2.2 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/klauspost/compress v1.18.6 // indirect
github.com/lib/pq v1.12.3 // indirect
Expand Down
4 changes: 2 additions & 2 deletions examples/using-add-filestore/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF2
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/jlaffaye/ftp v0.2.1 h1:AICcTYPMkaXlmjLMm9I+lB36f6jXCsCvBqVQc6EfC1Y=
github.com/jlaffaye/ftp v0.2.1/go.mod h1:gXSIr1pA9NhynDNigiFHs4+yL7o7I6bGF9Za9wi9tcE=
github.com/jlaffaye/ftp v0.2.2 h1:JwjrXCAIjN9ZYrF1/8qlmHFXDteh9MHYaiEIh/Oqtd8=
github.com/jlaffaye/ftp v0.2.2/go.mod h1:zuLAKdqFqFvNgkCrH0SC7K1XyUiydS7BFCmmoHUWWg0=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
Expand Down
2 changes: 1 addition & 1 deletion examples/using-add-rest-handlers/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-custom-metrics/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-file-bind/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-http-service/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-migrations/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-publisher/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion examples/using-subscriber/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.26
FROM golang:1.27

RUN mkdir /src/
WORKDIR /src/
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module gofr.dev

go 1.26.0
go 1.25.0

require (
cloud.google.com/go/pubsub v1.51.0
Expand Down
4 changes: 2 additions & 2 deletions pkg/gofr/http/middleware/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1018,9 +1018,9 @@ func Test_LoggingContract_RequestLogEscaping(t *testing.T) {
`{"uri":"/\u2028\u2029"}`,
},
{
"invalid UTF-8 bytes become the escaped replacement character",
"invalid UTF-8 bytes become the replacement character",
RequestLog{URI: "/\xff\xfe/ok"},
`{"uri":"/\ufffd\ufffd/ok"}`,
`{"uri":"/` + replacementInJSON + replacementInJSON + `/ok"}`,
},
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/gofr/http/middleware/replacement_go127_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build go1.27

package middleware

// replacementInJSON is how encoding/json renders U+FFFD inside a JSON string.
// See the !go1.27 file for why this moves with the toolchain.
const replacementInJSON = "�"
15 changes: 15 additions & 0 deletions pkg/gofr/http/middleware/replacement_pre_go127_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build !go1.27

package middleware

// replacementInJSON is how encoding/json renders U+FFFD — the character it
// substitutes for invalid UTF-8 — inside a JSON string.
//
// Up to Go 1.26 that is the six-character escape \ufffd. Go 1.27 rebuilt
// encoding/json on encoding/json/v2 and writes the rune itself instead. Both
// decode to the same string; only the bytes on the wire differ, and these tests
// exist to pin those bytes, so the expectation follows the toolchain.
//
// The switch belongs to the toolchain, not to us: a Go 1.27 build emits the raw
// rune whatever go directive go.mod declares.
const replacementInJSON = `\ufffd`
Loading