Help us shape the future of Go! Take the 2026 Go Developer Survey

store

package
v0.13.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

Documentation

Overview

Package store keeps a little workflow state on disk between sessions, in two SQLite databases under the OS-native data directory. workflow.db is the cache, what a session can see again: the commit scope last used in a repository, what was announced, and the last issue list seen. kept.db is what the user decided and a session cannot see again: whom a forge owner is on Slack, a repository's groups, and the favorite directories. Neither ever holds a secret, and callers key them only by credential-free identifiers.

Each schema is Third Normal Form and every table is STRICT: repeating groups — the cached issue list — are a parent row and one child row each, no derived value is stored, and each column's type is enforced at write time. Timestamps are RFC3339 UTC text, a child's foreign key cascades from the row that owns it and restricts toward a Slack user or group others share, and a write that replaces a group runs in one transaction. Callers sanitize text on the way in and treat what they read back as untrusted, since a file on disk can be tampered.

A store is a value, and a disabled one no-ops every method, so a caller need not special-case the privacy opt-out. Each operation opens its own short-lived connection, so there is no handle to close and the terminal interface and the web server can share the files; WAL and a busy timeout keep their writes from colliding.

Each file's schema has one version, stamped into it. A workflow.db written at another is discarded and started fresh, since what it held is seen again. A kept.db written at another is never discarded: it is left as it is, for the user to remove.

Index

Constants

This section is empty.

Variables

View Source
var ErrCleanRefused = errors.New("not the store's own files to clean")

ErrCleanRefused reports a clean that would reach past the store's own plain files: a relative directory, or a symlink or directory where a database file belongs. Nothing is removed.

View Source
var ErrInvalidOwner = errors.New("not a forge owner")

ErrInvalidOwner reports a forge owner not shaped like a CODEOWNERS user or team.

View Source
var ErrInvalidSlackID = errors.New("not a Slack ID of the right kind")

ErrInvalidSlackID reports a Slack ID of the wrong shape, or of the wrong kind for what it is linked to.

View Source
var ErrKeptSchemaDiffers = errors.New(
	"the kept data was written by a build of workflow with another schema; " +
		"run `workflow db-clean --all` to start it fresh")

ErrKeptSchemaDiffers reports a kept database written at another schema version than this build's. It is left as it is: it reads as empty, and a write is refused rather than risk what it holds.

View Source
var ErrNoDir = errors.New("could not determine a data directory for the store")

ErrNoDir reports that no OS-native data directory could be determined.

View Source
var ErrNoWorkspace = errors.New("no Slack workspace to keep Slack links under")

ErrNoWorkspace reports a Slack link read or made under no Slack workspace, whose links no one could tell from another workspace's.

View Source
var ErrNotADirectoryPath = errors.New("a favorite is an absolute path to a directory, written plainly")

ErrNotADirectoryPath is a favorite that is not an absolute, clean path.

View Source
var ErrNotCleaned = errors.New("could not remove a store file")

ErrNotCleaned reports a file a clean could not remove, as one another program holds open can be on Windows.

Functions

func Clean added in v0.5.0

func Clean(dir string, scope CleanScope) error

Clean removes the cache's database from dir, with its companions, and with CleanAll the kept data's too. It refuses, removing nothing, a relative dir or anything but a plain file where a database file belongs. Every file is set aside before any is removed, and one that cannot be set aside puts the rest back, so a file another program holds open fails the clean without leaving half a database behind. What an earlier clean set aside and could not remove goes first.

func DefaultDir

func DefaultDir() (string, error)

DefaultDir is the OS-native directory workflow keeps its store in, from the running machine's home and environment.

func Dir

func Dir(goos, home string, lookupEnv func(string) (string, bool)) (string, error)

Dir is the OS-native store directory for a platform, home and environment, taken as arguments so every platform's path can be exercised from one machine: %AppData%\workflow on Windows, ~/Library/Application Support/workflow on macOS, and $XDG_STATE_HOME or ~/.local/state/workflow elsewhere. A variable that is not an absolute path is ignored, as the XDG specification says to: joined, it would put the store wherever workflow happened to start.

func HumanBytes added in v0.9.0

func HumanBytes(size int64) string

HumanBytes is a size in bytes, KiB or MiB, with one decimal past bytes: how every surface shows a database file's size.

Types

type Announce

type Announce struct {
	Pull   int
	Moment int
}

Announce is one announcement made in a repository: which pull request, and the moment it marked — opened, or merged. The moment is an opaque int the interface assigns, so the store need not know the interface's vocabulary.

type CachedIssue

type CachedIssue struct {
	Key            string
	Summary        string
	Status         string
	StatusCategory string
	Type           string
	Priority       string
}

CachedIssue is the store's shape of a cached issue — the few non-secret fields a first pane needs, kept as the store's own type so it stays decoupled from the interface's domain type. status_category is stored beside status even though a Jira status maps to one category: the mapping is Jira's, not ours to derive.

type CleanScope added in v0.5.0

type CleanScope int

CleanScope says how much a clean removes.

const (
	CleanCache CleanScope = iota
	CleanAll
)

The scopes of a clean: the cache alone, or the kept data too.

func (CleanScope) Consequence added in v0.9.0

func (s CleanScope) Consequence() string

Consequence is what a clean of the scope takes with it, in the words every surface's last look warns with before anything is removed.

type DataFile added in v0.5.0

type DataFile struct {
	Name  string
	Kind  DataKind
	Bytes int64
	Holds []Held
}

DataFile is one database file in the store directory: its name, its kind, its size with its write-ahead log and shared-memory companions, and what it holds, where that could be read.

func Files added in v0.5.0

func Files(ctx context.Context, dir string) ([]DataFile, error)

Files lists the database files in dir, each with its size and what it holds, read without writing; a file not there is left out. What a clean set aside and could not remove is listed too, by the database's name and asideSuffix, so it is seen and the next clean takes it.

type DataKind added in v0.5.0

type DataKind string

DataKind says what a database file holds: conveniences a session sees again, or what the user decided.

const (
	DataCache DataKind = "cache"
	DataKept  DataKind = "kept"
)

The kinds of database file the store keeps.

type Favorite added in v0.6.0

type Favorite struct {
	Dir   string
	Added time.Time
}

Favorite is a directory you marked, and when.

type Held added in v0.5.0

type Held struct {
	What  string
	Count int
}

Held is a count of one kind of thing a database file holds.

type OwnerLink struct {
	Owner   string
	Team    bool
	OnSlack bool
	Slack   SlackTarget
}

OwnerLink is what was decided for one forge owner: whether they are a team, which links to a Slack user group, or a person, who links to a Slack user; whether they are on Slack; and if so, as whom.

type SlackTarget added in v0.5.0

type SlackTarget struct {
	ID    string
	Label string
}

SlackTarget is a Slack user or user group, by its ID and the label it was last seen with — the store's own shape, in plain strings.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store points at the on-disk store. Its zero value, and any disabled store, no-op every method, so persistence-off behaves exactly as no store at all.

func New

func New(dir string, disabled bool) Store

New points a store at dir. Disabled keeps the code path identical for a user who opts out of persistence: every method no-ops.

func (Store) Announces

func (s Store) Announces(ctx context.Context, repo string) ([]Announce, error)

Announces are every announcement recorded for a repository, so the interface can open knowing what has already been posted. A disabled store reports none.

func (Store) CacheIssues

func (s Store) CacheIssues(ctx context.Context, instance, view string, issues []CachedIssue, now time.Time) error

CacheIssues stores issues as the list last seen for a view of an instance, replacing any earlier one in a single transaction so a re-cache never leaves a half-updated view. A disabled or read-only store caches nothing.

func (Store) CachedIssues

func (s Store) CachedIssues(ctx context.Context, instance, view string) ([]CachedIssue, bool, error)

CachedIssues is the issue list last cached for a view of a Jira instance, in the tracker's order, and whether the view was cached at all — a view cached with no issues reports found with an empty slice, distinct from one never cached. A disabled store, or one with no instance, reports nothing.

func (Store) Favor added in v0.6.0

func (s Store) Favor(ctx context.Context, dir string, now time.Time) error

Favor marks dir a favorite, keeping when it was first marked. A row for dir whose time does not read back is one Favorites leaves out, so its time is written afresh rather than kept. A disabled or read-only store records nothing.

func (Store) Favorites added in v0.6.0

func (s Store) Favorites(ctx context.Context) ([]Favorite, error)

Favorites is the directories you marked, by path. A row of the wrong shape is left out. A disabled store, or one with none, reports none.

func (Store) ForgetOwner added in v0.5.0

func (s Store) ForgetOwner(ctx context.Context, forgeHost, workspace, owner string) error

ForgetOwner drops what was decided for a forge owner on a host in a Slack workspace, whatever the case of owner, so they are asked again there. What was decided in other workspaces is kept, and so then is the decision. A disabled or read-only store forgets nothing.

func (Store) Keeps added in v0.5.0

func (s Store) Keeps() bool

Keeps reports a store that keeps anything: neither disabled nor without a directory. A read-only store keeps what is already on disk, so it keeps.

func (Store) LastGroups added in v0.5.0

func (s Store) LastGroups(ctx context.Context, repo, workspace string) ([]string, bool, error)

LastGroups is the group IDs of a workspace last chosen for a repository's announcement, by ID, and whether a choice was recorded at all, in any workspace — a choice of no group is still one. An ID of the wrong shape is left out. A disabled store reports no choice.

func (Store) LastScope

func (s Store) LastScope(ctx context.Context, repo string) (string, bool, error)

LastScope is the commit scope last recorded for repo, and whether one was. A disabled store, or a repo with nothing recorded, reports no scope.

func (Store) LinkOwner added in v0.5.0

func (s Store) LinkOwner(ctx context.Context, forgeHost, workspace string, decision OwnerLink, now time.Time) error

LinkOwner records what was decided for a forge owner on a host in a Slack workspace, and whether they are a person or a team, as the caller tells: whom they are on Slack there, or that they are not on Slack there, replacing only that workspace's decision. It refuses an owner of the wrong shape for its kind with ErrInvalidOwner, a Slack ID of the wrong shape or kind — a user group for a team, a user for a person — with ErrInvalidSlackID, and a decision under no workspace with ErrNoWorkspace. The owner is kept in lower case, since both forges read user and team names without regard to case. A disabled or read-only store records nothing.

func (s Store) OwnerLinks(ctx context.Context, forgeHost, workspace string) ([]OwnerLink, error)

OwnerLinks is every owner decided on a forge host as a Slack workspace sees them, by owner in lower case: linked there, or decided not on Slack there. An owner decided only in other workspaces is left out, so they read as never decided here and are asked again. A row of the wrong shape — a tampered or corrupt file's — is left out too, and each label is sanitized and capped. A disabled store, or a host with nothing decided, reports none.

func (Store) ReadOnly added in v0.4.0

func (s Store) ReadOnly() Store

ReadOnly is the store for a dry run: it reads what is already on disk, reads nothing where there is no store yet rather than create one, and no-ops every write.

func (Store) RecordAnnounce

func (s Store) RecordAnnounce(ctx context.Context, repo string, announce Announce, now time.Time) error

RecordAnnounce remembers that a pull request was announced at a moment, so a later session knows not to offer announcing it again. A disabled or read-only store records nothing.

func (Store) RecordGroups added in v0.5.0

func (s Store) RecordGroups(ctx context.Context, repo, workspace string, ids []string, now time.Time) error

RecordGroups remembers the groups of a workspace just chosen for a repository's announcement, replacing that workspace's last choice in one transaction. Only the repository's own groups are remembered: an announcement also tags groups linked to owning teams, which need not be listed, and refusing the whole choice over one of those would lose the rest of it. A disabled or read-only store records nothing.

func (Store) RecordScope

func (s Store) RecordScope(ctx context.Context, repo, scope string, now time.Time) error

RecordScope remembers scope as the one last used in repo, replacing any earlier one. A disabled or read-only store records nothing.

func (Store) RepoGroups added in v0.5.0

func (s Store) RepoGroups(ctx context.Context, repo, workspace string) ([]SlackTarget, error)

RepoGroups is the Slack user groups of a workspace a repository may tag, by label. A row of the wrong shape is left out, and each label is sanitized and capped. A disabled store, or a repository with none, reports none.

func (Store) SetRepoGroups added in v0.5.0

func (s Store) SetRepoGroups(ctx context.Context, repo, workspace string, groups []SlackTarget, now time.Time) error

SetRepoGroups replaces the Slack user groups of a workspace a repository may tag, in one transaction, leaving other workspaces' groups as they are. It refuses any ID not a group's with ErrInvalidSlackID, and groups under no workspace with ErrNoWorkspace. A group dropped from the list drops out of the last choice too. A disabled or read-only store records nothing.

func (Store) Unfavor added in v0.6.0

func (s Store) Unfavor(ctx context.Context, dir string) error

Unfavor forgets dir as a favorite. A disabled or read-only store changes nothing.

func (Store) Writes added in v0.6.0

func (s Store) Writes() bool

Writes reports a store that records what it is told: kept on, somewhere to keep it, and not read-only.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL