Documentation
¶
Overview ¶
Package originbind owns one invariant: a workspace is bound to one origin.
Both surfaces that can change which origin owns a workspace live behind it — `gadak init` and PUT onboarding/connect/ — so the decision cannot exist on one path and not the other. That split is exactly how GDK-247 happened: the CLI path was closed and the unauthenticated HTTP path was not.
It is not part of internal/workspace, which mounts profiles under /w/ and imports internal/server: the server calls this, so that would cycle.
Index ¶
- Constants
- func CanonicalSite(raw string) string
- func ClearStandalone(next *config.Config)
- func DropStandaloneProjection(cfg *config.Config, db *store.DB) (store.OriginReset, error)
- func LocalData(cfg *config.Config) (n int, persist string, err error)
- func ParseProjectKeys(s string) []string
- func RefuseIfOpen(cfg *config.Config) error
- func RefuseReplace(cfg *config.Config, replace bool) error
- func RefuseSiteRebind(cfg *config.Config, newSite string) error
- func SeedStandalone(cfg *config.Config, projectsCSV string, spaces []string, ...) (fillErr error, err error)
- type MirrorOpener
- type ReplaceRefusedError
- type SiteBoundError
- type WorkspaceOpenError
Constants ¶
const ErrCodeReplaceRefused = "standalone_data_present"
ErrCodeReplaceRefused is the --json / HTTP "error" value when a connected init or onboarding connect refuses to take over a standalone workspace that holds data. The string is a CLI --json contract; do not change it.
Variables ¶
This section is empty.
Functions ¶
func CanonicalSite ¶ added in v0.17.0
CanonicalSite is the compare key for site rebind: scheme + host, no path, no trailing slash. Scheme-less input is treated as https, matching internal/server.normalizeSite.
func ClearStandalone ¶
ClearStandalone is the single owner of "origin is now a Jira site, so this workspace is no longer standalone". Reached only after RefuseReplace (or an explicit replace opt-in). Empty standalone workspaces take this path too: once connected, Kind must be cleared.
func DropStandaloneProjection ¶ added in v0.16.1
DropStandaloneProjection is the conversion cleanup both CLI init and HTTP onboarding must run: drop the seeded LOC wiki scope, then hand both sources to the store's origin-replacement owner.
What that owner removes is decided by the table classification in internal/store/origin_scope.go, not here. It used to be a literal list of DELETEs, and four tables added by later migrations were never added to it — so a converted workspace kept plugin enrichments, feed read marks, field usage and sync runs that named the retired origin's keys, which do not go stale but rebind to whatever the new site put at the same key (GDK-418).
The returned OriginReset is what to tell the user; an empty String() means nothing personal was bound to the old origin.
func LocalData ¶
LocalData reports how much locally originated data this standalone workspace holds, and the origin persist path (via origin.PersistPath — never rebuilt from string pieces). The returned n is max(issues, pages).
Each of issues and pages is itself max(mirror, origin):
- mirror: SELECT COUNT(*) FROM issues / pages, only if gadak.db exists (store.Open would create it)
- origin issues: Search on the in-process origin, only if the persist file or a sibling legacy YAML already exists (origin.Client would create an empty persist)
- origin pages: wiki SearchPages, best-effort (a SearchPages miss is 0, not a LocalData failure — issuetap may not implement CQL)
init --standalone creates a persist file with a project fixture and no issues or pages, so that empty-origin case is n==0 and the common "I tried it, now I want to connect" path is not blocked.
func ParseProjectKeys ¶ added in v0.19.0
ParseProjectKeys splits a comma-separated project list the way init always has: trim, upper-case, drop empties. Exported because POST onboarding/standalone parses its body with the same rule — one function, not two parsers kept in step by review.
func RefuseIfOpen ¶ added in v0.16.1
RefuseIfOpen stops a CLI standalone→connected conversion while another process has this workspace open. HTTP conversion runs inside the owner process and must not call this.
Two questions, because one answer does not cover both holders:
A live `gadak serve` is found through the home-root run directory (serveaddr) and an identity probe — not leftover serve-origin.json, which GDK-936 made meaningless. Gadak.app opens no port at all (its assets go through a custom scheme handler), so serveaddr cannot see it. The persist's open marker can (GDK-971). That marker is advisory and never arbitrates writes — WAL does that — it only says someone is holding this workspace.
func RefuseReplace ¶
RefuseReplace stops a connected init / onboarding connect from silently changing which origin owns a standalone workspace that holds locally originated data. An empty standalone workspace (tried it, nothing filed) is not a hazard and is allowed through.
JSON rendering stays at the CLI call site — this returns an error only.
func RefuseSiteRebind ¶ added in v0.17.0
RefuseSiteRebind stops a connected init / onboarding connect from silently re-pointing a workspace at a different site. Empty cfg.Site is first bind (or standalone/paired with no site) and is allowed. Same site after CanonicalSite is token rotation and is allowed.
func SeedStandalone ¶ added in v0.19.0
func SeedStandalone(cfg *config.Config, projectsCSV string, spaces []string, openMirror MirrorOpener) (fillErr error, err error)
SeedStandalone turns cfg into a standalone workspace: it mutates and saves the config, resolves and records the default issue type, and fills the mirror so the next command is not "stale, run sync".
Already-standalone is not detected here — callers need it before the call (the CLI prints a one-line idempotent path); compute cfg.IsStandalone() first if you need it.
A fill that fails does not fail the seed: the workspace exists, its persist file is written, and writes already work. That contract moved here from initStandalone — returning a fatal error would break `init --standalone --json && gadak create …` over something the next `gadak sync` fixes. The fill failure comes back as fillErr instead; the caller decides how to surface it (CLI: stderr warning; serve: log line).
The origin flush (origin.Close) is deliberately NOT here: it is the CLI process-exit path. A serve holds the origin session for its lifetime.
spaces is the wiki space set the workspace syncs; nil keeps the seeded default (LOC). migrate passes the space keys its fixture carries, so the first fill mirrors them instead of a space the fixture does not contain.
Types ¶
type MirrorOpener ¶ added in v0.19.0
MirrorOpener hands SeedStandalone a mirror store and the release that must run after the fill. The CLI opens a fresh store and closes it; a serve process passes its already-open store back with a no-op release — that handle lives as long as the process does and must not be closed under a running server.
type ReplaceRefusedError ¶
ReplaceRefusedError is returned when RefuseReplace blocks a connect. Error() is the human sentence previously printed by gadak init.
func (*ReplaceRefusedError) Error ¶
func (e *ReplaceRefusedError) Error() string
type SiteBoundError ¶ added in v0.17.0
type SiteBoundError struct {
Bound string
}
SiteBoundError is returned when a connected workspace is asked to bind a different site. Issue keys are not globally unique; changing origin means a new workspace (package comment). Error() is the CLI/HTTP sentence.
func (*SiteBoundError) Error ¶ added in v0.17.0
func (e *SiteBoundError) Error() string
type WorkspaceOpenError ¶ added in v0.16.1
WorkspaceOpenError is returned when CLI conversion would run while another process (serve or the desktop app) has this workspace open.
func (*WorkspaceOpenError) Error ¶ added in v0.16.1
func (e *WorkspaceOpenError) Error() string