Skip to content
Open
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
2 changes: 1 addition & 1 deletion action.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package api

import (
"encoding/json"
"encoding/json/v2"
)

//go:generate stringer -type=Action -linecomment
Expand Down
2 changes: 1 addition & 1 deletion auditactortype.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package api

import "encoding/json"
import "encoding/json/v2"

//go:generate stringer -type=AuditActorType -linecomment
type AuditActorType int
Expand Down
2 changes: 1 addition & 1 deletion auditoutcome.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package api

import "encoding/json"
import "encoding/json/v2"

//go:generate stringer -type=AuditOutcome -linecomment
type AuditOutcome int
Expand Down
6 changes: 3 additions & 3 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package client
import (
"bytes"
"context"
"encoding/json"
"encoding/json/v2"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -185,7 +185,7 @@ func (c *Client) invoke(ctx context.Context, api string, r any, res any) error {
}

var reqBody bytes.Buffer
err := json.NewEncoder(&reqBody).Encode(r)
err := json.MarshalWrite(&reqBody, r)
if err != nil {
return err
}
Expand Down Expand Up @@ -222,7 +222,7 @@ func (c *Client) invoke(ctx context.Context, api string, r any, res any) error {
respBody.Result = res
respBody.Error = &errMsg

err = json.NewDecoder(resp.Body).Decode(&respBody)
err = json.UnmarshalRead(resp.Body, &respBody)
if err != nil {
return err
}
Expand Down
18 changes: 9 additions & 9 deletions client/dropbox_create_upload_url.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package client
import (
"bytes"
"context"
"encoding/json"
"encoding/json/v2"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -32,10 +32,10 @@ type DropboxCreateUploadURLOptions struct {
Project string `json:"project" yaml:"project"` // project sid the upload is authorized and billed against
Filename string `json:"filename,omitempty" yaml:"filename"` // optional filename recorded in Content-Disposition for downloads
ContentType string `json:"contentType,omitempty" yaml:"contentType"` // optional; when set, the PUT must send this exact Content-Type
MinSize int64 `json:"minSize,omitempty" yaml:"minSize"` // optional min bytes; the server floors it at 1 so empty uploads are refused
MaxSize int64 `json:"maxSize,omitempty" yaml:"maxSize"` // optional max bytes; the server clamps to its cap (default 5 GiB)
TTLDays int `json:"ttl,omitempty" yaml:"ttl"` // download lifetime in days, 1-7; 0 -> server default 1
Expires int `json:"expires,omitempty" yaml:"expires"` // upload-URL validity in seconds, 1-3600; 0 -> server default 900
MinSize int64 `json:"minSize,omitzero" yaml:"minSize"` // optional min bytes; the server floors it at 1 so empty uploads are refused
MaxSize int64 `json:"maxSize,omitzero" yaml:"maxSize"` // optional max bytes; the server clamps to its cap (default 5 GiB)
TTLDays int `json:"ttl,omitzero" yaml:"ttl"` // download lifetime in days, 1-7; 0 -> server default 1
Expires int `json:"expires,omitzero" yaml:"expires"` // upload-URL validity in seconds, 1-3600; 0 -> server default 900
Endpoint string `json:"-" yaml:"-"` // optional dropbox base URL override; empty -> DefaultDropboxEndpoint
}

Expand Down Expand Up @@ -86,10 +86,10 @@ func (c *Client) DropboxCreateUploadURL(ctx context.Context, opts *DropboxCreate
Project string `json:"project"`
Filename string `json:"filename,omitempty"`
ContentType string `json:"contentType,omitempty"`
MinSize int64 `json:"minSize,omitempty"`
MaxSize int64 `json:"maxSize,omitempty"`
TTL int `json:"ttl,omitempty"`
Expires int `json:"expires,omitempty"`
MinSize int64 `json:"minSize,omitzero"`
MaxSize int64 `json:"maxSize,omitzero"`
TTL int `json:"ttl,omitzero"`
Expires int `json:"expires,omitzero"`
}{
Project: opts.Project,
Filename: opts.Filename,
Expand Down
2 changes: 1 addition & 1 deletion client/dropbox_upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package client
import (
"bytes"
"context"
"encoding/json"
"encoding/json/v2"
"fmt"
"io"
"net/http"
Expand Down
55 changes: 55 additions & 0 deletions client/jsonv2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package client

import (
"strings"
"testing"

json "encoding/json/v2"
)

func TestDropboxOptionalIntsOmitted(t *testing.T) {
got, err := json.Marshal(DropboxCreateUploadURLOptions{Project: "p"})
if err != nil {
t.Fatal(err)
}
s := string(got)
for _, k := range []string{"minSize", "maxSize", "ttl", "expires"} {
if strings.Contains(s, k) {
t.Fatalf("zero %s should be omitted, got %s", k, s)
}
}
if s != `{"project":"p"}` {
t.Fatalf("got %s", s)
}
}

func TestSiteManifestDeterministic(t *testing.T) {
m := siteManifest{
Environment: "production",
Files: map[string]siteManifestEntry{
"z.txt": {Blob: "b", CT: "text/plain", Cache: "html"},
"a.html": {Blob: "a", CT: "text/html", Cache: "html"},
},
}
var prev string
for range 20 {
b, err := json.Marshal(m, json.Deterministic(true))
if err != nil {
t.Fatal(err)
}
if prev == "" {
prev = string(b)
continue
}
if string(b) != prev {
t.Fatalf("non-deterministic marshal:\n %s\n %s", prev, b)
}
}
if !strings.Contains(prev, `"a.html"`) || !strings.Contains(prev, `"z.txt"`) {
t.Fatalf("missing files: %s", prev)
}
// Sorted map keys: a.html before z.txt.
if i, j := strings.Index(prev, `"a.html"`), strings.Index(prev, `"z.txt"`); i < 0 || j < 0 || i > j {
t.Fatalf("files keys not sorted: %s", prev)
}
}
4 changes: 2 additions & 2 deletions client/notification_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"bufio"
"bytes"
"context"
"encoding/json"
"encoding/json/v2"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -79,7 +79,7 @@ func (c *Client) NotificationPullStream(ctx context.Context, m *api.Notification
}

var body bytes.Buffer
if err := json.NewEncoder(&body).Encode(m); err != nil {
if err := json.MarshalWrite(&body, m); err != nil {
return err
}

Expand Down
13 changes: 7 additions & 6 deletions client/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"encoding/json/jsontext"
"encoding/json/v2"
"fmt"
"io"
"io/fs"
Expand Down Expand Up @@ -88,8 +89,8 @@ func (r *SitePublishResult) Table() [][]string {

// siteManifestEntry / siteManifest mirror the apiserver's release manifest JSON
// shape. The release-sha the server content-addresses against is sha256 of the
// exact manifest bytes we PUT; encoding/json sorts map keys, so the bytes are
// deterministic for a given input.
// exact manifest bytes we PUT; Marshal uses json.Deterministic so map keys are
// sorted and the bytes are stable for a given input.
type siteManifestEntry struct {
Blob string `json:"blob"`
CT string `json:"ct"`
Expand Down Expand Up @@ -259,7 +260,7 @@ func (c *Client) PublishSite(ctx context.Context, opts *SitePublishOptions) (*Si
SPA: opts.SPA,
NotFound: opts.NotFound,
Files: files,
})
}, json.Deterministic(true))
if err != nil {
return nil, fmt.Errorf("site: encode manifest: %w", err)
}
Expand Down Expand Up @@ -321,8 +322,8 @@ func (c *Client) siteDo(ctx context.Context, method, p string, q url.Values, bod
// failures; other guard failures (bad session, sha mismatch) return a
// plain-text body via http.Error.
var env struct {
OK bool `json:"ok"`
Result json.RawMessage `json:"result"`
OK bool `json:"ok"`
Result jsontext.Value `json:"result"`
Error struct {
Message string `json:"message"`
} `json:"error"`
Expand Down
84 changes: 42 additions & 42 deletions deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ type DeployerIsDomainActive struct {
type GetCommandsResult []*DeployerCommandItem

type DeployerCommandItem struct {
PullSecretCreate *DeployerCommandPullSecretCreate `json:"pullSecretCreate,omitempty"`
PullSecretDelete *DeployerCommandMetadata `json:"pullSecretDelete,omitempty"`
WorkloadIdentityCreate *DeployerCommandWorkloadIdentityCreate `json:"workloadIdentityCreate,omitempty"`
WorkloadIdentityDelete *DeployerCommandMetadata `json:"workloadIdentityDelete,omitempty"`
DiskCreate *DeployerCommandDiskCreate `json:"diskCreate,omitempty"`
DiskDelete *DeployerCommandMetadata `json:"diskDelete,omitempty"`
DeploymentDeploy *DeployerCommandDeploymentDeploy `json:"deploymentDeploy,omitempty"`
DeploymentDelete *DeployerCommandDeploymentMetadata `json:"deploymentDelete,omitempty"`
DeploymentPause *DeployerCommandDeploymentMetadata `json:"deploymentPause,omitempty"`
DeploymentCleanup *DeployerCommandDeploymentMetadata `json:"deploymentCleanup,omitempty"`
RouteCreate *DeployerCommandRouteCreate `json:"routeCreate,omitempty"`
RouteDelete *DeployerCommandRouteDelete `json:"routeDelete,omitempty"`
DomainCertCreate *DeployerCommandDomainCertCreate `json:"domainCertCreate,omitempty"`
DomainCertDelete *DeployerCommandDomainCertDelete `json:"domainCertDelete,omitempty"`
WAFSet *DeployerCommandWAFSet `json:"wafSet,omitempty"`
WAFDelete *DeployerCommandWAFDelete `json:"wafDelete,omitempty"`
CacheSet *DeployerCommandCacheSet `json:"cacheSet,omitempty"`
CacheDelete *DeployerCommandCacheDelete `json:"cacheDelete,omitempty"`
TransformSet *DeployerCommandTransformSet `json:"transformSet,omitempty"`
TransformDelete *DeployerCommandTransformDelete `json:"transformDelete,omitempty"`
PullSecretCreate *DeployerCommandPullSecretCreate `json:"pullSecretCreate,omitzero"`
PullSecretDelete *DeployerCommandMetadata `json:"pullSecretDelete,omitzero"`
WorkloadIdentityCreate *DeployerCommandWorkloadIdentityCreate `json:"workloadIdentityCreate,omitzero"`
WorkloadIdentityDelete *DeployerCommandMetadata `json:"workloadIdentityDelete,omitzero"`
DiskCreate *DeployerCommandDiskCreate `json:"diskCreate,omitzero"`
DiskDelete *DeployerCommandMetadata `json:"diskDelete,omitzero"`
DeploymentDeploy *DeployerCommandDeploymentDeploy `json:"deploymentDeploy,omitzero"`
DeploymentDelete *DeployerCommandDeploymentMetadata `json:"deploymentDelete,omitzero"`
DeploymentPause *DeployerCommandDeploymentMetadata `json:"deploymentPause,omitzero"`
DeploymentCleanup *DeployerCommandDeploymentMetadata `json:"deploymentCleanup,omitzero"`
RouteCreate *DeployerCommandRouteCreate `json:"routeCreate,omitzero"`
RouteDelete *DeployerCommandRouteDelete `json:"routeDelete,omitzero"`
DomainCertCreate *DeployerCommandDomainCertCreate `json:"domainCertCreate,omitzero"`
DomainCertDelete *DeployerCommandDomainCertDelete `json:"domainCertDelete,omitzero"`
WAFSet *DeployerCommandWAFSet `json:"wafSet,omitzero"`
WAFDelete *DeployerCommandWAFDelete `json:"wafDelete,omitzero"`
CacheSet *DeployerCommandCacheSet `json:"cacheSet,omitzero"`
CacheDelete *DeployerCommandCacheDelete `json:"cacheDelete,omitzero"`
TransformSet *DeployerCommandTransformSet `json:"transformSet,omitzero"`
TransformDelete *DeployerCommandTransformDelete `json:"transformDelete,omitzero"`
}

type DeployerCommandMetadata struct {
Expand Down Expand Up @@ -302,26 +302,26 @@ type DeployerCommandTransformDelete struct {
type DeployerSetResult []*DeployerSetResultItem

type DeployerSetResultItem struct {
PullSecretCreate *DeployerSetResultItemGeneral `json:"pullSecretCreate,omitempty"`
PullSecretDelete *DeployerSetResultItemGeneral `json:"pullSecretDelete,omitempty"`
WorkloadIdentityCreate *DeployerSetResultItemGeneral `json:"workloadIdentityCreate,omitempty"`
WorkloadIdentityDelete *DeployerSetResultItemGeneral `json:"workloadIdentityDelete,omitempty"`
DiskCreate *DeployerSetResultItemGeneral `json:"diskCreate,omitempty"`
DiskDelete *DeployerSetResultItemGeneral `json:"diskDelete,omitempty"`
DeploymentDeploy *DeployerSetResultItemDeploy `json:"deploymentDeploy,omitempty"`
DeploymentDelete *DeployerSetResultItemGeneral `json:"deploymentDelete,omitempty"`
DeploymentPause *DeployerSetResultItemDeployment `json:"deploymentPause,omitempty"`
DeploymentCleanup *DeployerSetResultItemDeployment `json:"deploymentCleanup,omitempty"`
RouteCreate *DeployerSetResultItemGeneral `json:"routeCreate,omitempty"`
RouteDelete *DeployerSetResultItemGeneral `json:"routeDelete,omitempty"`
DomainCertCreate *DeployerSetResultItemDomainCert `json:"domainCertCreate,omitempty"`
DomainCertDelete *DeployerSetResultItemGeneral `json:"domainCertDelete,omitempty"`
WAFSet *DeployerSetResultItemGeneral `json:"wafSet,omitempty"`
WAFDelete *DeployerSetResultItemGeneral `json:"wafDelete,omitempty"`
CacheSet *DeployerSetResultItemGeneral `json:"cacheSet,omitempty"`
CacheDelete *DeployerSetResultItemGeneral `json:"cacheDelete,omitempty"`
TransformSet *DeployerSetResultItemGeneral `json:"transformSet,omitempty"`
TransformDelete *DeployerSetResultItemGeneral `json:"transformDelete,omitempty"`
PullSecretCreate *DeployerSetResultItemGeneral `json:"pullSecretCreate,omitzero"`
PullSecretDelete *DeployerSetResultItemGeneral `json:"pullSecretDelete,omitzero"`
WorkloadIdentityCreate *DeployerSetResultItemGeneral `json:"workloadIdentityCreate,omitzero"`
WorkloadIdentityDelete *DeployerSetResultItemGeneral `json:"workloadIdentityDelete,omitzero"`
DiskCreate *DeployerSetResultItemGeneral `json:"diskCreate,omitzero"`
DiskDelete *DeployerSetResultItemGeneral `json:"diskDelete,omitzero"`
DeploymentDeploy *DeployerSetResultItemDeploy `json:"deploymentDeploy,omitzero"`
DeploymentDelete *DeployerSetResultItemGeneral `json:"deploymentDelete,omitzero"`
DeploymentPause *DeployerSetResultItemDeployment `json:"deploymentPause,omitzero"`
DeploymentCleanup *DeployerSetResultItemDeployment `json:"deploymentCleanup,omitzero"`
RouteCreate *DeployerSetResultItemGeneral `json:"routeCreate,omitzero"`
RouteDelete *DeployerSetResultItemGeneral `json:"routeDelete,omitzero"`
DomainCertCreate *DeployerSetResultItemDomainCert `json:"domainCertCreate,omitzero"`
DomainCertDelete *DeployerSetResultItemGeneral `json:"domainCertDelete,omitzero"`
WAFSet *DeployerSetResultItemGeneral `json:"wafSet,omitzero"`
WAFDelete *DeployerSetResultItemGeneral `json:"wafDelete,omitzero"`
CacheSet *DeployerSetResultItemGeneral `json:"cacheSet,omitzero"`
CacheDelete *DeployerSetResultItemGeneral `json:"cacheDelete,omitzero"`
TransformSet *DeployerSetResultItemGeneral `json:"transformSet,omitzero"`
TransformDelete *DeployerSetResultItemGeneral `json:"transformDelete,omitzero"`
}

type DeployerSetResultItemGeneral struct {
Expand All @@ -338,14 +338,14 @@ type DeployerSetResultItemGeneral struct {
// historical behavior), so the gate is correct regardless of deploy order.
type DeployerSetResultItemDomainCert struct {
ID int64 `json:"id"`
Ready *bool `json:"ready,omitempty"`
Ready *bool `json:"ready,omitzero"`
}

type DeployerSetResultItemDeploy struct {
ID int64 `json:"id"`
Revision int64 `json:"revision"`
Success bool `json:"success"`
NodePort *int `json:"nodePort,omitempty"`
NodePort *int `json:"nodePort,omitzero"`
}

type DeployerSetResultItemDeployment struct {
Expand Down
2 changes: 1 addition & 1 deletion deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package api

import (
"context"
"encoding/json"
"encoding/json/v2"
"fmt"
"path/filepath"
"strconv"
Expand Down
2 changes: 1 addition & 1 deletion deploymentaction.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package api

import "encoding/json"
import "encoding/json/v2"

//go:generate stringer -type=DeploymentAction -linecomment
type DeploymentAction int
Expand Down
6 changes: 3 additions & 3 deletions domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type DomainItem struct {
// show how long a cert has been issuing and warn as it nears the reclaim
// window. Cleared once the cert issues (created) or is torn down.
CertStatus DomainCertStatus `json:"certStatus" yaml:"certStatus"`
CertPendingSince time.Time `json:"certPendingSince,omitempty" yaml:"certPendingSince,omitempty"`
CertPendingSince time.Time `json:"certPendingSince,omitzero" yaml:"certPendingSince,omitempty"`
CreatedAt time.Time `json:"createdAt" yaml:"createdAt"`
CreatedBy string `json:"createdBy" yaml:"createdBy"`
}
Expand All @@ -114,8 +114,8 @@ type DomainVerification struct {
// location's load balancer (directly or via a proxy with a matching ownership
// TXT). LastCheckedAt is the most recent attempt.
type DomainVerificationDNS struct {
VerifiedAt time.Time `json:"verifiedAt,omitempty"`
LastCheckedAt time.Time `json:"lastCheckedAt,omitempty"`
VerifiedAt time.Time `json:"verifiedAt,omitzero"`
LastCheckedAt time.Time `json:"lastCheckedAt,omitzero"`
Errors []string `json:"errors,omitempty"`
}

Expand Down
2 changes: 1 addition & 1 deletion domaincertstatus.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package api

import "encoding/json"
import "encoding/json/v2"

//go:generate stringer -type=DomainCertStatus -linecomment
type DomainCertStatus int
Expand Down
2 changes: 1 addition & 1 deletion domainstatus.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package api

import "encoding/json"
import "encoding/json/v2"

//go:generate stringer -type=DomainStatus -linecomment
type DomainStatus int
Expand Down
2 changes: 1 addition & 1 deletion email.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package api

import (
"context"
"encoding/json"
"encoding/json/v2"
"fmt"
"strings"
"time"
Expand Down
2 changes: 1 addition & 1 deletion errors.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package api

import (
"encoding/json"
"encoding/json/v2"
"fmt"
"slices"
"strings"
Expand Down
Loading