Skip to content
Merged
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
6 changes: 4 additions & 2 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
directories:
- "**/*"
schedule:
interval: "weekly"
day: "friday"
Expand All @@ -27,7 +28,8 @@ updates:
# 2. golang.org-dependencies are auto-merged
# 3. go-openapi patch updates are auto-merged. Minor/major version updates require a manual merge.
# 4. other dependencies require a manual merge
directory: "/"
directories:
- "**/*"
schedule:
interval: "weekly"
day: "friday"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ jobs:
permissions:
contents: write
pull-requests: write
uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11
uses: go-openapi/ci-workflows/.github/workflows/auto-merge.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
secrets: inherit
29 changes: 11 additions & 18 deletions .github/workflows/bump-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,15 @@ permissions:
on:
workflow_dispatch:
inputs:
bump-patch:
description: Bump a patch version release
type: boolean
bump-type:
description: Type of bump (patch, minor, major)
type: choice
options:
- patch
- minor
- major
default: patch
required: false
default: true
bump-minor:
description: Bump a minor version release
type: boolean
required: false
default: false
bump-major:
description: Bump a major version release
type: boolean
required: false
default: false
tag-message-title:
description: Tag message title to prepend to the release notes
required: false
Expand All @@ -36,11 +30,10 @@ jobs:
bump-release:
permissions:
contents: write
uses: go-openapi/ci-workflows/.github/workflows/bump-release.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11
pull-requests: write
uses: go-openapi/ci-workflows/.github/workflows/bump-release-monorepo.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
with:
bump-patch: ${{ inputs.bump-patch }}
bump-minor: ${{ inputs.bump-minor }}
bump-major: ${{ inputs.bump-major }}
bump-type: ${{ inputs.bump-type }}
tag-message-title: ${{ inputs.tag-message-title }}
tag-message-body: ${{ inputs.tag-message-body }}
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ jobs:
permissions:
contents: read
security-events: write
uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11
uses: go-openapi/ci-workflows/.github/workflows/codeql.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ jobs:
permissions:
pull-requests: write
contents: write
uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11
uses: go-openapi/ci-workflows/.github/workflows/contributors.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/go-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ on:

jobs:
test:
uses: go-openapi/ci-workflows/.github/workflows/go-test.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11
uses: go-openapi/ci-workflows/.github/workflows/go-test-monorepo.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:

- uses: actions/setup-go@v5
with:
go-version-file: go.mod
go-version: stable

- name: Run integration tests
working-directory: internal/testintegration
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ jobs:
permissions:
contents: read
security-events: write
uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # V0.2.11
uses: go-openapi/ci-workflows/.github/workflows/scanner.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
secrets: inherit
3 changes: 2 additions & 1 deletion .github/workflows/tag-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ jobs:
name: Create release
permissions:
contents: write
uses: go-openapi/ci-workflows/.github/workflows/release.yml@435746a4b72b06b6b6989c309fd2ad8150dbae5a # v0.2.11
uses: go-openapi/ci-workflows/.github/workflows/release.yml@34a5baa33361844b1d2c70cd4548e3cea83529d9 # v0.2.13
with:
tag: ${{ github.ref_name }}
is-monorepo: true
secrets: inherit
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ You may join the discord community by clicking the invite link on the discord ba

Or join our Slack channel: [![Slack Channel][slack-logo]![slack-badge]][slack-url]

* **2026-03-07** : v0.26.0 **dropped dependency to the mongodb driver**
* mongodb users can still use this package without any change
* however, we have frozen the back-compatible support for mongodb driver at v2.5.0
* users who want to keep-up with future evolutions (possibly incompatible) of this driver
can do so by adding a blank import in their program: `import _ "github.com/go-openapi/strfmt/enable/mongodb"`.
This will switch the behavior to the actual driver, which remains regularly updated as an independent module.

## Status

API is stable.
Expand Down Expand Up @@ -132,8 +139,9 @@ List of defined types:
All format types implement the `database/sql` interfaces `sql.Scanner` and `driver.Valuer`,
so they work out of the box with Go's standard `database/sql` package and any SQL driver.

All format types also implement BSON marshaling/unmarshaling for use with MongoDB
(via [`go.mongodb.org/mongo-driver/v2`](https://pkg.go.dev/go.mongodb.org/mongo-driver/v2)).
All format types also implement BSON marshaling/unmarshaling for use with MongoDB.
By default, a built-in minimal codec is used (compatible with mongo-driver v2.5.0).
For full driver support, add `import _ "github.com/go-openapi/strfmt/enable/mongodb"`.

> **MySQL / MariaDB caveat for `DateTime`:**
> The `go-sql-driver/mysql` driver has hard-coded handling for `time.Time` but does not
Expand Down
69 changes: 47 additions & 22 deletions bson.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ package strfmt

import (
"database/sql/driver"
"encoding/hex"
"encoding/json"
"fmt"

bsonprim "go.mongodb.org/mongo-driver/v2/bson"
)

func init() { //nolint:gochecknoinits // registers bsonobjectid format in the default registry
Expand All @@ -17,45 +17,46 @@ func init() { //nolint:gochecknoinits // registers bsonobjectid format in the de

// IsBSONObjectID returns true when the string is a valid BSON [ObjectId].
func IsBSONObjectID(str string) bool {
_, err := bsonprim.ObjectIDFromHex(str)
_, err := objectIDFromHex(str)
return err == nil
}

// ObjectId represents a BSON object ID (alias to [primitive.ObjectID]).
// ObjectId represents a BSON object ID (a 12-byte unique identifier).
//
// swagger:[strfmt] bsonobjectid.
type ObjectId bsonprim.ObjectID //nolint:revive
// swagger:strfmt bsonobjectid.
type ObjectId [12]byte //nolint:revive

// nilObjectID is the zero-value ObjectId.
var nilObjectID ObjectId //nolint:gochecknoglobals // package-level sentinel

// NewObjectId creates a [ObjectId] from a Hex String.
// NewObjectId creates a [ObjectId] from a hexadecimal String.
func NewObjectId(hex string) ObjectId { //nolint:revive
oid, err := bsonprim.ObjectIDFromHex(hex)
oid, err := objectIDFromHex(hex)
if err != nil {
panic(err)
}
return ObjectId(oid)
return oid
}

// MarshalText turns this instance into text.
func (id ObjectId) MarshalText() ([]byte, error) {
oid := bsonprim.ObjectID(id)
if oid == bsonprim.NilObjectID {
if id == nilObjectID {
return nil, nil
}
return []byte(oid.Hex()), nil
return []byte(id.Hex()), nil
}

// UnmarshalText hydrates this instance from text.
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
if len(data) == 0 {
*id = ObjectId(bsonprim.NilObjectID)
*id = nilObjectID
return nil
}
oidstr := string(data)
oid, err := bsonprim.ObjectIDFromHex(oidstr)
oid, err := objectIDFromHex(string(data))
if err != nil {
return err
}
*id = ObjectId(oid)
*id = oid
return nil
}

Expand All @@ -76,25 +77,34 @@ func (id *ObjectId) Scan(raw any) error {

// Value converts a value to a database driver value.
func (id ObjectId) Value() (driver.Value, error) {
return driver.Value(bsonprim.ObjectID(id).Hex()), nil
return driver.Value(id.Hex()), nil
}

// Hex returns the hex string representation of the [ObjectId].
func (id ObjectId) Hex() string {
return hex.EncodeToString(id[:])
}

func (id ObjectId) String() string {
return bsonprim.ObjectID(id).Hex()
return id.Hex()
}

// MarshalJSON returns the [ObjectId] as JSON.
func (id ObjectId) MarshalJSON() ([]byte, error) {
return bsonprim.ObjectID(id).MarshalJSON()
return json.Marshal(id.Hex())
}

// UnmarshalJSON sets the [ObjectId] from JSON.
func (id *ObjectId) UnmarshalJSON(data []byte) error {
var obj bsonprim.ObjectID
if err := obj.UnmarshalJSON(data); err != nil {
var hexStr string
if err := json.Unmarshal(data, &hexStr); err != nil {
return err
}
oid, err := objectIDFromHex(hexStr)
if err != nil {
return err
}
*id = ObjectId(obj)
*id = oid
return nil
}

Expand All @@ -112,3 +122,18 @@ func (id *ObjectId) DeepCopy() *ObjectId {
id.DeepCopyInto(out)
return out
}

// objectIDFromHex parses a 24-character hex string into an [ObjectId].
func objectIDFromHex(s string) (ObjectId, error) {
const objectIDHexLen = 24
if len(s) != objectIDHexLen {
return nilObjectID, fmt.Errorf("the provided hex string %q is not a valid ObjectID: %w", s, ErrFormat)
}
b, err := hex.DecodeString(s)
if err != nil {
return nilObjectID, fmt.Errorf("the provided hex string %q is not a valid ObjectID: %w", s, err)
}
var oid ObjectId
copy(oid[:], b)
return oid, nil
}
5 changes: 2 additions & 3 deletions bson_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/go-openapi/testify/v2/assert"
"github.com/go-openapi/testify/v2/require"
"go.mongodb.org/mongo-driver/v2/bson"
)

func TestBSONObjectId_fullCycle(t *testing.T) {
Expand Down Expand Up @@ -39,10 +38,10 @@ func TestBSONObjectId_fullCycle(t *testing.T) {
require.NoError(t, err)
assert.EqualT(t, id, idCopy)

bsonBytes, err := bson.Marshal(&id)
bsonBytes, err := id.MarshalBSON()
require.NoError(t, err)

err = bson.Unmarshal(bsonBytes, &idCopy)
err = idCopy.UnmarshalBSON(bsonBytes)
require.NoError(t, err)
assert.EqualT(t, id, idCopy)
}
Expand Down
2 changes: 1 addition & 1 deletion default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func TestFormatIPv4(t *testing.T) {
func TestFormatIPv6(t *testing.T) {
ipv6 := IPv6("::1")
str := string("::2")
// TODO: test ipv6 zones
// Proposal for enhancement: test ipv6 zones
testStringFormat(t, &ipv6, "ipv6", str, []string{}, []string{"127.0.0.1"})
}

Expand Down
2 changes: 0 additions & 2 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@
// SPDX-License-Identifier: Apache-2.0

// Package strfmt contains custom string formats.
//
// TODO: add info on how to define and register a custom format.
package strfmt
39 changes: 18 additions & 21 deletions docs/MAINTAINERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@

## Repo structure

This project is organized as a repo with a single go module.
This project is organized as a mono-repo with multiple go modules:

| Module | Description |
|--------|-------------|
| `.` (root) | Core `strfmt` package with all format types |
| `enable/mongodb` | Blank-import package that replaces the built-in minimal BSON codec with the real MongoDB driver |
| `internal/testintegration` | Integration tests against real databases (MongoDB, MariaDB, PostgreSQL) |

A `go.work` file at the root ties all modules together for local development.

## Repo configuration

Expand Down Expand Up @@ -54,7 +62,7 @@ Coverage threshold status is informative and not blocking.
This is because the thresholds are difficult to tune and codecov oftentimes reports false negatives
or may fail to upload coverage.

All tests across `go-openapi` use our fork of `stretchr/strfmt` (this repo): `github.com/go-openapi/strfmt`.
All tests across `go-openapi` use our fork of `stretchr/testify`: `github.com/go-openapi/testify`.
This allows for minimal test dependencies.

> **NOTES**
Expand Down Expand Up @@ -117,19 +125,20 @@ Reports are centralized in github security reports for code scanning tools.

## Releases

**For single module repos:**

A bump release workflow can be triggered from the github actions UI to cut a release with a few clicks.
A bump release workflow (mono-repo) can be triggered from the github actions UI to cut a release with a few clicks.

The release process is minimalist:
The release process updates cross-module dependencies (e.g. `enable/mongodb` → root module)
before pushing the desired git tag.

* push a semver tag (i.e v{major}.{minor}.{patch}) to the master branch.
* the CI handles this to generate a github release with release notes
It first creates an auto-merged PR that updates the different `go.mod` files,
then pushes the desired semver tag.

* release notes generator: git-cliff <https://git-cliff.org/docs/>
* configuration: the `.cliff.toml` is defined as a share configuration on
* configuration: the `.cliff.toml` is defined as a shared configuration on
remote repo [`ci-workflows/.cliff.toml`][remote-cliff-config]

Commits and tags pushed by the workflow bot are PGP-signed ("go-openapi[bot]").

Commits from maintainers are preferably PGP-signed.

Tags are preferably PGP-signed.
Expand All @@ -140,18 +149,6 @@ The tag message introduces the release notes (e.g. a summary of this release).

The release notes generator does not assume that commits are necessarily "conventional commits".

**For mono-repos with multiple modules:**

The release process is slightly different because we need to update cross-module dependencies
before pushing a tag.

A bump release workflow (mono-repo) can be triggered from the github actions UI to cut a release with a few clicks.

It works with the same input as the one for single module repos, and first creates a PR (auto-merged)
that updates the different go.mod files _before_ pushing the desired git tag.

Commits and tags pushed by the workflow bot are PGP-signed ("go-openapi[bot]").

## Other files

Standard documentation:
Expand Down
2 changes: 1 addition & 1 deletion duration.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ func ParseDuration(cand string) (time.Duration, error) {
// Scan reads a Duration value from database driver type.
func (d *Duration) Scan(raw any) error {
switch v := raw.(type) {
// TODO: case []byte: // ?
// Proposal for enhancement: case []byte: // ?
case int64:
*d = Duration(v)
case float64:
Expand Down
Loading
Loading