Documentation
¶
Index ¶
- Constants
- func ComputeHash(data []byte) string
- func FindMetaFiles(projectRoot, localDir string) (map[string]*AssetMeta, error)
- func MetaPath(projectRoot, assetAbs string) (string, error)
- func WriteMeta(metaPath string, meta *AssetMeta) error
- type AssetMeta
- type AssetStatus
- type CreateMode
- type DiffEntry
- type DiffType
- type FileStatus
- type FolderCreated
- type Matcher
- type PullResult
- type PushResult
- type RefreshResult
- type RefreshState
- type SyncEngine
- func (e *SyncEngine) ClassifyEntry(ctx context.Context, entry config.SyncEntry) (RefreshResult, error)
- func (e *SyncEngine) Diff(entry config.SyncEntry) ([]DiffEntry, error)
- func (e *SyncEngine) EnableFolderListCache()
- func (e *SyncEngine) FoldersCreated() []FolderCreated
- func (e *SyncEngine) Pull(entry config.SyncEntry, force, skipErrors bool) ([]PullResult, error)
- func (e *SyncEngine) Push(entry config.SyncEntry, dryRun bool, preserveState bool, force bool) ([]PushResult, error)
- func (e *SyncEngine) SetCreateMode(mode CreateMode)
- func (e *SyncEngine) Status(entry config.SyncEntry) ([]AssetStatus, error)
Constants ¶
const IgnoreFile = ".wkignore"
IgnoreFile is the filename at the project root whose patterns exclude files and directories from sync operations (ADR-005 Decision 10).
Variables ¶
This section is empty.
Functions ¶
func ComputeHash ¶
ComputeHash returns the SHA256 hex digest of data.
func FindMetaFiles ¶
FindMetaFiles scans the .wk/ mirror tree for metas describing assets whose asset path is under localDir. Keys in the returned map are asset paths relative to localDir, so callers can compare them directly against filepath.Walk rel-paths of the asset tree.
Types ¶
type AssetMeta ¶
type AssetMeta struct {
ServerPath string `json:"server_path"`
ZipName string `json:"zip_name"`
Folder string `json:"folder"`
Type string `json:"type"` // "recipe", "connection"
Version int `json:"version"`
RecipeName string `json:"recipe_name,omitempty"`
ContentHash string `json:"content_hash"` // SHA256
LastPulledAt time.Time `json:"last_pulled_at"`
}
AssetMeta is the sidecar metadata stored for each synced asset.
Per ADR-005 Decision 1, metas live under the project's .wk/ mirror tree — the asset at <root>/<rel> has its meta at <root>/.wk/<rel>.meta.json. Meta files never sit next to assets.
RecipeName is populated only when Type == "recipe" and the JSON body in the pull zip contained a parsable top-level "name" field. The Workato package-manifest zip intentionally omits server-side IDs (the wk recipes export endpoint is the only source for those), so downstream local-cleanup paths (e.g. wk recipes delete) match by name — resolving an ID to a name via a single API call first.
type AssetStatus ¶
type AssetStatus struct {
FilePath string `json:"file_path"`
Status FileStatus `json:"status"`
ServerPath string `json:"server_path,omitempty"` // from meta, if available
}
AssetStatus represents the sync status of a single asset file.
type CreateMode ¶
type CreateMode int
CreateMode controls folderIDForEntry's fallback behavior when the hierarchy walk fails to resolve an entry's server_path (ADR-007 Decision 13). Default (zero value) is CreateModeBareNames.
const ( // CreateModeBareNames creates a missing top-level folder when the // server_path has no slashes — the greenfield pattern. Nested paths // still error; auto-creating a multi-level tree on first push is // more likely to mask a typo than to match intent. CreateModeBareNames CreateMode = iota // CreateModeNever disables auto-create entirely. Any missing folder // surfaces as an error. The --no-create CI escape hatch. CreateModeNever // CreateModeAnyPath creates missing folders at any depth, walking // parents and creating each segment in order. The --create-path // escape hatch for deliberately spinning up a nested hierarchy. CreateModeAnyPath )
type DiffEntry ¶
type DiffEntry struct {
Path string `json:"path"`
Type DiffType `json:"type"`
LocalHash string `json:"local_hash,omitempty"`
RemoteHash string `json:"remote_hash,omitempty"`
}
DiffEntry describes the diff state of a single asset path.
type DiffType ¶
type DiffType string
DiffType describes how a local asset differs from its remote counterpart.
type FileStatus ¶
type FileStatus string
FileStatus describes the local state of a synced asset.
const ( StatusUnchanged FileStatus = "unchanged" StatusModified FileStatus = "modified" StatusNew FileStatus = "new" // local file with no .meta.json sidecar in .wk/ StatusDeleted FileStatus = "deleted" // .meta.json exists in .wk/ but asset file is gone )
type FolderCreated ¶
type FolderCreated struct {
ServerPath string `json:"server_path"`
FolderID int `json:"folder_id"`
ProjectID int `json:"project_id,omitempty"`
}
FolderCreated records one server-side folder creation triggered by push's resolve-then-create branch (ADR-007 Decision 14). One record per API call — under --create-path a single entry may produce multiple records (one per missing segment). ProjectID is non-zero when the API marked the created folder as a project (is_project=true); it is the separate identifier required by DELETE /projects/{project_id}.
type Matcher ¶
type Matcher struct {
// contains filtered or unexported fields
}
Matcher evaluates paths against a set of .wkignore patterns.
Semantics follow the subset of gitignore documented in ADR-005 Decision 10:
- `*` matches within a single path component
- `**` matches across path separators
- a trailing `/` restricts the pattern to directories
- a leading `!` negates a previous match
- `#` begins a comment; blank lines are ignored
- all patterns evaluate relative to the project root
Anything beyond this spec (leading-slash anchoring beyond the default, re-inclusion after parent exclusion, character classes) is intentionally out of scope.
func LoadMatcher ¶
LoadMatcher reads <projectRoot>/.wkignore and returns a compiled Matcher. If the file is absent, returns a non-nil Matcher that matches nothing (default: include everything).
func (*Matcher) Match ¶
Match reports whether relPath (project-root-relative, forward slashes) should be ignored. isDir disambiguates directory-only patterns.
Evaluation is last-match-wins, so a later negating pattern can re-include a previously matched path.
func (*Matcher) ShouldSkip ¶
ShouldSkip reports whether the walker should skip a path entirely. This combines the implicit .wk/ skip (regardless of .wkignore content, ADR-005 Decision 10) with the user's .wkignore rules.
relPath must be project-root-relative using forward slashes.
type PullResult ¶
type PullResult struct {
FilePath string `json:"file_path"`
// Action is one of: "created", "updated", "unchanged", "skipped",
// "deleted" (server-side delete reconciled locally), "orphaned"
// (server-side deleted but local copy was modified — kept on disk),
// or "error" (per-file failure when --skip-errors is active).
Action string `json:"action"`
Error string `json:"error,omitempty"`
}
PullResult describes what happened to a single file during pull.
type PushResult ¶
type PushResult struct {
FilePath string `json:"file_path"`
Action string `json:"action"` // "created", "updated", "deleted", "unchanged" (dry-run)
}
PushResult describes what happened to a single file during push.
type RefreshResult ¶
type RefreshResult struct {
ServerPath string `json:"server_path"`
LocalPath string `json:"local_path"`
FolderID int `json:"folder_id,omitempty"`
ProjectID int `json:"project_id,omitempty"`
State RefreshState `json:"state"`
Message string `json:"message,omitempty"`
}
RefreshResult is the per-entry outcome emitted by ClassifyEntry. ServerPath / LocalPath come from the incoming entry; FolderID is either the resolved ID (found / current / repaired) or the cached ID from before classification (not-found, so the developer can still see what the local wk.toml had). ProjectID mirrors the same policy for the distinct project identifier (populated when the folder is a project, zero otherwise). Message carries a human detail string for repaired / not-found; empty for found / current.
type RefreshState ¶
type RefreshState string
RefreshState is the per-entry outcome of `wk sync refresh` (ADR-007 Decision 11). Values are stable across human and JSON output so downstream scripts can branch on the string literally.
const ( // RefreshStateFound: entry had no cached folder_id and the walk // succeeded. First-time resolution — no drift involved. The new ID // has been written into the in-memory config slot; callers save // once per sweep. RefreshStateFound RefreshState = "found" // RefreshStateCurrent: entry had a cached folder_id and the walk // returned the same ID. No cache change needed. RefreshStateCurrent RefreshState = "current" // RefreshStateRepaired: entry had a cached folder_id but the walk // returned a different ID (renamed folder, recreated with a new // ID, workspace swap, etc.). Drift was detected; the cache has // been rewritten with the fresh ID. CI monitors can alert on this // state to see that the workspace changed underfoot. RefreshStateRepaired RefreshState = "repaired" // RefreshStateNotFound: walk failed — server_path does not describe // a real folder. Reported; --prune removes. Entries that had a // cached folder_id still show it in the output so the developer can // see "used to work" vs "never worked"; the distinction is in the // data, not in a separate state label. RefreshStateNotFound RefreshState = "not-found" )
type SyncEngine ¶
type SyncEngine struct {
// contains filtered or unexported fields
}
SyncEngine coordinates pull, push, status, and diff operations between the local project directory and the Workato workspace.
func NewSyncEngine ¶
NewSyncEngine creates a SyncEngine wired to the given project and API client. client may be nil for local-only operations (e.g. status).
func (*SyncEngine) ClassifyEntry ¶
func (e *SyncEngine) ClassifyEntry(ctx context.Context, entry config.SyncEntry) (RefreshResult, error)
ClassifyEntry reconciles one [sync] entry against current server state (ADR-007 Decision 11). The Workato API does not expose a single-folder-by-ID endpoint, so cache validation happens by walking the hierarchy via List and comparing the resolved leaf ID against the cached value. On a fresh resolution (found) or cache repair (repaired), writes the new folder_id into the matching config slot in memory; callers persist via config.Save once the full sweep has run.
Returns a non-nil error only for genuine API failures (auth, 5xx, network). "Name not present under expected parent" is distinguished from API failure via the errPathNotResolved sentinel that resolveFolderID wraps into its error, and classifies the entry as not-found rather than halting the sweep.
func (*SyncEngine) Diff ¶
func (e *SyncEngine) Diff(entry config.SyncEntry) ([]DiffEntry, error)
Diff compares local files against remote state for a sync entry. This requires API access to fetch the remote package.
func (*SyncEngine) EnableFolderListCache ¶
func (e *SyncEngine) EnableFolderListCache()
EnableFolderListCache turns on per-parent List memoization for this engine. Safe to call once before a batch of ClassifyEntry calls. Pull/push/status should NOT enable this — they can see mid-run server changes and must reach the API freshly.
func (*SyncEngine) FoldersCreated ¶
func (e *SyncEngine) FoldersCreated() []FolderCreated
FoldersCreated returns the server-folder creations that have happened during this engine's lifetime. Reset is caller-scoped: a fresh engine always starts empty. Safe to call once after all Push invocations complete.
Always returns a non-nil slice so JSON consumers see "[]" rather than "null" when nothing was created — keeps scripts that destructure folders_created from having to special-case the empty case.
func (*SyncEngine) Pull ¶
func (e *SyncEngine) Pull(entry config.SyncEntry, force, skipErrors bool) ([]PullResult, error)
Pull downloads remote assets to the local project directory. If force is false, it aborts when a locally modified file would be overwritten by the fresh export — but only if that file is still present server-side. Files that were modified locally AND removed server-side are NOT conflicts: reconcileDeletions reports them as "orphaned" and leaves them on disk untouched. That narrower semantic means the overwrite check must run after the zip is in hand, not before.
func (*SyncEngine) Push ¶
func (e *SyncEngine) Push(entry config.SyncEntry, dryRun bool, preserveState bool, force bool) ([]PushResult, error)
Push uploads local assets to the remote workspace. If dryRun is true, it reports what would be pushed without making changes. preserveState controls whether recipe active state is preserved on import. If force is true, all tracked files are pushed regardless of local change status.
func (*SyncEngine) SetCreateMode ¶
func (e *SyncEngine) SetCreateMode(mode CreateMode)
SetCreateMode configures how folderIDForEntry handles a failed walk for uncached entries. Call once during command setup, after flag parsing. Default (zero value) is CreateModeBareNames.
func (*SyncEngine) Status ¶
func (e *SyncEngine) Status(entry config.SyncEntry) ([]AssetStatus, error)
Status computes the local modification state for a sync entry. This is a purely local operation -- no API calls are made.