Go SDK
The Go SDK lives at sdk/go/docstore and is a separate Go module (github.com/dlorenc/docstore/sdk/go/docstore).
Installation
go get github.com/dlorenc/docstore/sdk/go/docstore
While the server module is untagged (monorepo development), the SDK's go.mod uses a replace directive to point at the local tree. For external consumers, this will be dropped once the server publishes a tag.
Creating a client
import "github.com/dlorenc/docstore/sdk/go/docstore"
client, err := docstore.NewClient("https://docstore.dev",
docstore.WithBearerToken("your-token"),
)
if err != nil {
log.Fatal(err)
}
Client options
| Option | Description |
|---|---|
WithBearerToken(token string) |
Sets Authorization: Bearer <token> on every request. |
WithIdentity(identity string) |
Sets X-DocStore-Identity header (dev mode only — server must have DEV_IDENTITY set). |
WithHTTPClient(h *http.Client) |
Replaces the default http.DefaultClient. Use for custom timeouts, proxies, or an IAP-authenticated transport. |
WithUserAgent(ua string) |
Overrides the User-Agent header (default: docstore-go-sdk/0.1). |
Repo-scoped operations
Use Client.Repo("owner/name") to get a *RepoClient scoped to a specific repository:
repo := client.Repo("acme/platform")
RepoClient is cheap to construct and safe for concurrent use.
Reading files
// Read from the head of main (default).
file, err := repo.File(ctx, "config.yaml", docstore.AtHead("main"))
fmt.Printf("%s: %s\n", file.Path, string(file.Content))
// Read at a specific sequence.
file, err = repo.File(ctx, "config.yaml", docstore.AtSequence(42))
// Read at a named release.
file, err = repo.File(ctx, "config.yaml", docstore.AtRelease("v1.0.0"))
Listing the tree
tree, err := repo.Tree(ctx, docstore.TreeAtHead("feature/x"))
for _, entry := range tree.Entries {
fmt.Println(entry.Path, entry.ContentType)
}
Committing files
import "github.com/dlorenc/docstore/api"
resp, err := repo.Commit(ctx, api.CommitRequest{
Branch: "feature/x",
Message: "update config",
Files: []api.FileChange{
{Path: "config.yaml", Content: []byte("version: 2\n")},
// Nil content deletes the file:
{Path: "old.txt", Content: nil},
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println("sequence:", resp.Sequence)
Branch operations
// List branches.
branches, err := repo.Branches(ctx)
// Create a branch.
_, err = repo.CreateBranch(ctx, api.CreateBranchRequest{Name: "feature/x"})
// Get branch metadata.
branch, err := repo.Branch(ctx, "feature/x")
// Check merge policy status.
status, err := repo.BranchStatus(ctx, "feature/x")
fmt.Println("mergeable:", status.Mergeable)
for _, p := range status.Policies {
fmt.Printf(" %s: pass=%v reason=%s\n", p.Name, p.Pass, p.Reason)
}
// Delete a branch.
_, err = repo.DeleteBranch(ctx, "feature/x")
Merge and rebase
// Merge a branch into main.
result, err := repo.Merge(ctx, api.MergeRequest{Branch: "feature/x"})
if err != nil {
// Check for conflict or policy error:
var conflict *docstore.ConflictError
var policyErr *docstore.PolicyError
if errors.As(err, &conflict) {
fmt.Println("conflicts:", conflict.Paths)
} else if errors.As(err, &policyErr) {
fmt.Println("policy denied:", policyErr.Results)
}
}
// Rebase a branch.
_, err = repo.Rebase(ctx, api.RebaseRequest{Branch: "feature/x"})
Diff
diff, err := repo.Diff(ctx, "feature/x")
for _, change := range diff.Changes {
fmt.Printf("%s (%s)\n", change.Path, change.Status)
}
Reviews and checks
// Submit a review.
_, err = repo.SubmitReview(ctx, api.CreateReviewRequest{
Branch: "feature/x",
Status: api.ReviewApproved,
Body: "LGTM",
})
// List reviews.
reviews, err := repo.Reviews(ctx, "feature/x")
// Report a CI check.
_, err = repo.ReportCheck(ctx, api.CreateCheckRunRequest{
Branch: "feature/x",
CheckName: "ci/build",
Status: api.CheckRunPassed,
})
// List checks.
checks, err := repo.Checks(ctx, "feature/x")
Roles
// List roles.
roles, err := repo.Roles(ctx)
// Set a role.
err = repo.SetRole(ctx, "bob@example.com", api.RoleWriter)
// Delete a role.
err = repo.DeleteRole(ctx, "bob@example.com")
Releases
// Create a release at the current head.
release, err := repo.CreateRelease(ctx, api.CreateReleaseRequest{
Name: "v1.0.0",
Notes: "First stable release",
})
// List releases.
releases, err := repo.ListReleases(ctx)
// Get a release.
release, err = repo.GetRelease(ctx, "v1.0.0")
// Delete a release (admin-only).
err = repo.DeleteRelease(ctx, "v1.0.0")
Chain verification
chain, err := repo.ChainSegment(ctx, 1, 50)
// Verify hash links locally...
Purge (admin-only)
result, err := repo.Purge(ctx, api.PurgeRequest{OlderThan: "720h"})
Org and repo management
orgs := client.Orgs()
repos := client.Repos()
// Create an org.
org, err := orgs.Create(ctx, "acme")
// List orgs.
list, err := orgs.List(ctx)
// Create a repo.
repo, err := repos.Create(ctx, api.CreateRepoRequest{Owner: "acme", Name: "platform"})
Error types
| Type | How to match | Returned when |
|---|---|---|
*docstore.ConflictError |
errors.As |
Merge or rebase has conflicts |
*docstore.PolicyError |
errors.As |
Merge rejected by a policy |
docstore.ErrNotFound |
errors.Is |
404 response |
docstore.ErrUnauthorized |
errors.Is |
401 response |
docstore.ErrForbidden |
errors.Is |
403 response |
docstore.ErrConflict |
errors.Is |
409 response (non-merge) |
Use errors.As for *ConflictError and *PolicyError; use errors.Is for the sentinel values.
Complete example
package main
import (
"context"
"fmt"
"log"
"github.com/dlorenc/docstore/api"
"github.com/dlorenc/docstore/sdk/go/docstore"
)
func main() {
client, err := docstore.NewClient("https://docstore.dev",
docstore.WithBearerToken("your-token"),
)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
repo := client.Repo("acme/platform")
// Read the current config.
file, err := repo.File(ctx, "config.yaml", docstore.AtHead("main"))
if err != nil {
log.Fatal(err)
}
fmt.Printf("config.yaml: %s\n", string(file.Content))
// Commit a change on a branch.
_, err = repo.Commit(ctx, api.CommitRequest{
Branch: "feature/update-config",
Message: "bump version to 3",
Files: []api.FileChange{
{Path: "config.yaml", Content: []byte("version: 3\n")},
},
})
if err != nil {
log.Fatal(err)
}
}
Raw markdown — machine-readable source for this page.