sync

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: Apache-2.0 Imports: 26 Imported by: 0

Documentation

Overview

Package sync orchestrates one complete synchronization.

A synchronization is the whole path from an upstream release to the exact set of outward actions publishing it would perform: the module is generated, its tree is written into the destination repository, the release commit is replayed, the release tag is projected, the resumable state record is stored, and the refs that would name all of it are planned. Nothing is pushed.

Planning and publishing are separate on purpose, and the separation is the point of the package. Every object a synchronization writes is unreachable until a ref names it, so a plan can be computed, compared between machines, attached to a review, and thrown away without anything outward having happened. Publication is a second call that takes the hash of the plan that was approved and refuses anything else.

The package name shadows the standard library's sync. It is the noun this engine's operation is called, and no file here needs goroutine primitives; an importer that needs both aliases one of them.

Index

Constants

View Source
const ManifestSchema = 1

ManifestSchema is the version of the manifest shape. An approval names a hash, and a hash of a shape the reader does not know is not an approval of anything it can check.

View Source
const ReconcileSchema = 1
View Source
const WriteVerificationSchema = 1

Variables

View Source
var (
	// ErrApproval reports an approval that does not name this manifest. It is
	// this package's own rather than publish.ErrApproval, because the hash an
	// operator approves covers the whole synchronization and not only the refs
	// it would move.
	ErrApproval = errors.New("approval does not name this synchronization")

	// ErrManifestModified reports a manifest that was changed after it was
	// rendered, which is what a recomputed hash disagreeing with the recorded
	// one means.
	ErrManifestModified = errors.New("synchronization manifest does not match its own hash")

	// ErrManifestLocation reports a manifest string that names the machine the
	// run happened on. The manifest is compared between machines and kept as the
	// record of what was authorized, so a path, a URL, or a line break in one of
	// its free-form strings is a refusal rather than something to render
	// carefully.
	ErrManifestLocation = errors.New("synchronization manifest must carry no path, URL, or control character")

	// ErrUnsupported reports a run shape this engine refuses rather than
	// approximates. It is neither a bad profile nor a broken engine: it is work
	// that has not been implemented, and producing an approximate answer for it
	// would publish history nobody designed.
	ErrUnsupported = errors.New("run shape is not supported by this engine")

	// ErrPublicationDisabled reports an apply asked for without a configured way
	// to reach the destination. A synchronization plans by default and publishes
	// only when it was given both a credentialed way to push and an approval, so
	// the absence of either is a refusal rather than a plan silently becoming a
	// publication.
	ErrPublicationDisabled = errors.New("publication requires a configured destination remote")
)

The refusals this package can produce.

They are separate from the ones the composed packages raise, because a synchronization refuses for reasons none of its parts can see: an approval that names a different plan, a resume shape this engine does not implement, and a publication asked for without anything to publish with.

View Source
var ErrWorkflowBudget = errors.New("the workflow budget cannot start another replay chunk")

Functions

func ApplyCheckpoint added in v0.2.0

func ApplyCheckpoint(ctx context.Context, result *ChunkResult, approval string, dryRun bool) (*publish.Result, error)

ApplyCheckpoint applies only the non-consumer scope of an approved chunk plan.

func ApplyReconciliation added in v0.2.0

func ApplyReconciliation(ctx context.Context, result *ReconciliationResult, approval string) (*publish.Result, error)

ApplyReconciliation applies only the state update of an exact-hash approved adoption plan.

Types

type AdoptedBranch added in v0.2.0

type AdoptedBranch struct {
	// Ref is the fully qualified branch ref.
	Ref string
	// Object is the commit the branch points at.
	Object string
	// Source is the upstream source commit from the cursor.
	Source string
}

AdoptedBranch is a legacy branch that state does not record in Published. The branch was verified against state cursors and the local HEAD, and the caller must record it in the outward manifest as a state-reconciliation item.

type AdoptedTag added in v0.2.0

type AdoptedTag struct {
	// Ref is the fully qualified tag ref.
	Ref string
	// Tag is the short destination tag name.
	Tag string
	// Object is the annotated tag object OID on the remote.
	Object string
	// Commit is the commit the tag peels to.
	Commit string
	// Source is the upstream source commit recorded in the provenance trailer.
	Source string
}

AdoptedTag is a legacy tag that exists on the remote without a matching state entry. Only the profile's configured firstTag is eligible for adoption; all other unrecorded tags are fatal.

type ApplyOptions

type ApplyOptions struct {
	// Approval is the synchronization manifest hash the operator approved after
	// reading it. It is required, and it is the only way this package learns
	// that publication was authorized: the hash covers the module, the objects,
	// and every ref that would move, so an approval that still matches is an
	// approval of exactly this synchronization.
	Approval string
	// DryRun performs every validation and every remote read and stops before
	// the pushes. It is how a run proves an approved publication would succeed
	// without performing it.
	DryRun bool
}

ApplyOptions configures one execution of an approved synchronization.

type ApplyResult

type ApplyResult struct {
	// NonConsumer is the state and progress push: engine bookkeeping no module
	// consumer and no module proxy can see.
	NonConsumer *Outcome
	// Consumer is the branch and tag push: what a module user resolves.
	Consumer *Outcome
	// DryRun reports that nothing was pushed because the caller asked for a
	// rehearsal.
	DryRun bool
}

ApplyResult reports what one Apply did.

The two halves are reported separately because they are two pushes, and the order between them is load bearing rather than incidental. A caller that needs to know whether a failure left the release published reads Consumer: a nil Consumer after a non-nil NonConsumer says the bookkeeping landed and the release was never attempted, and a Consumer with Failed set says it was attempted and says which of its refs are now live.

func Apply

func Apply(ctx context.Context, result *Result, opts ApplyOptions) (*ApplyResult, error)

Apply publishes an approved synchronization.

The approval is checked against the manifest's own hash, and the manifest is checked against its own contents first. Checking the manifest before the approval is what makes the check mean anything: an approval compared against a hash field that was edited alongside the actions it covers would match a manifest nobody read.

The non-consumer half goes first, and the two halves are separate pushes. That order is the whole reason the scopes exist. The state record says where the engine got to; the branch and the tag are what a consumer and the module proxy resolve. Publishing the release first and failing before the record lands leaves a destination whose published history the next run cannot account for, whereas publishing the record first and failing before the release leaves a record of work whose refs simply have not appeared yet, which is a resumable state rather than a corrupt one.

A failure in the consumer half is returned with the non-consumer result still attached, because "the bookkeeping is published and the release is not" is precisely what the operator needs to be told.

type BehaviorSummary

type BehaviorSummary struct {
	Summary string `json:"summary"`
	Cause   string `json:"cause"`
}

BehaviorSummary is one documented difference from upstream.

type ChunkOptions added in v0.2.0

type ChunkOptions struct {
	Config      *config.Config
	Discovery   *Discovery
	SourceCache *source.Cache
	Destination Destination
	Generate    generate.Options
	Release     source.Release
	Budget      WorkflowBudget
}

ChunkOptions describes one resumable progress step toward a pending release.

type ChunkResult added in v0.2.0

type ChunkResult struct {
	DAG      *DAGResult
	Track    state.Track
	Document state.Document
	State    state.Record
	Mapping  []byte
	Publish  *publish.Plan
	Complete bool
	// contains filtered or unexported fields
}

ChunkResult holds a non-consumer checkpoint plan. Applying Publish moves only the state and progress refs; the consumer branch and release tag remain still.

func PlanChunk added in v0.2.0

func PlanChunk(ctx context.Context, opts ChunkOptions) (*ChunkResult, error)

PlanChunk projects and records one source-history chunk without moving a ref.

type ControlPlaneBranch added in v0.2.1

type ControlPlaneBranch struct {
	// Ref is the fully qualified branch ref.
	Ref string
	// Base is the generated commit state last observed.
	Base string
	// Object is the current control-plane branch head.
	Object string
	// Source is the source commit Base was generated from.
	Source string
}

ControlPlaneBranch is a verified fast-forward of the consumer branch that changes only operator-owned paths. State continues to name Base as the image of Source; Object is the graft point a future replay must preserve.

type DAGOptions added in v0.2.0

type DAGOptions struct {
	Config         *config.Config
	SourceCache    *source.Cache
	DestinationGit *gitcli.Runner
	Generate       generate.Options

	// AnchorCommit bounds the range below. MappedAnchor maps it onto
	// EpochParent without regenerating a destination commit. AnchorTag seeds the
	// watched closure for a published release anchor; an intermediate progress
	// anchor leaves it empty and is generated as an exact commit for analysis.
	AnchorCommit string
	AnchorTag    string
	// HistoryAnchorCommit and HistoryAnchorTag keep intermediate dependency
	// mapping bounded by the last published release across progress checkpoints.
	// Empty adopts AnchorCommit and AnchorTag.
	HistoryAnchorCommit string
	HistoryAnchorTag    string
	MappedAnchor        bool
	EpochParent         string

	// HeadCommit optionally stops before the release head for a checkpoint. Empty
	// means the complete pending release.
	HeadCommit string
	// Release is the pending source release bounding every checkpoint.
	Release source.Release
}

DAGOptions describes one release-bounded relevant-DAG replay. The source release tag has already been fetched and discovered; this phase reads only exact commits from that cache and writes unreachable objects to the local destination repository.

type DAGResult added in v0.2.0

type DAGResult struct {
	Replay             *replay.Result
	HeadCommit         string
	HeadGeneration     *generate.Result
	ReleaseGeneration  *generate.Result
	WatchedPaths       []string
	GeneratedCommits   int
	PrefilteredCommits int
}

DAGResult is the locally projected relevant history. ReleaseGeneration is the exact generated module used at the release head and is ready for release projection; no ref has moved.

func ReplayDAG added in v0.2.0

func ReplayDAG(ctx context.Context, opts DAGOptions) (*DAGResult, error)

ReplayDAG transforms the source DAG from AnchorCommit through Release.

type DependencySummary

type DependencySummary struct {
	// Policy is the configured default action.
	Policy string `json:"policy"`
	// Copy lists the staging paths the decision approves, sorted. For a profile
	// whose answer is external it is empty, and that emptiness is the decision.
	Copy []string `json:"copy"`
	// Candidates, Copied, and Refused summarize the decision.
	Candidates int `json:"candidates"`
	Copied     int `json:"copied"`
	Refused    int `json:"refused"`
}

DependencySummary is what the dependency policy decided.

type Destination

type Destination struct {
	// Git is the runner bound to the local destination repository. Every object
	// this run writes is written there, and it is the runner the publication
	// pushes with.
	//
	// It is handed over already built rather than assembled here, because a real
	// publication needs a runner carrying a credential helper and this package
	// must never invent one: it does not know how the operator's token is
	// stored, and a runner it built would either carry no credential or carry one
	// this package had to have been told. A caller publishing over https supplies
	// a runner whose environment already authenticates.
	Git *gitcli.Runner
	// Remote is the push target: an https URL on the publication host, or an
	// absolute path when AllowLocalRemote is set.
	Remote string
	// Identity is the canonical destination repository recorded in every
	// manifest, such as github.com/enj/rbac_authorizer. An https remote derives
	// it; a local remote must state it, because the alternative is a temporary
	// directory in an approved artifact.
	Identity string
	// AllowLocalRemote permits a path or file URL destination. It is off by
	// default so a mistyped configuration cannot publish into a directory, and a
	// local dry run turns it on explicitly.
	AllowLocalRemote bool
	// Lister reads the refs the destination advertises. A nil value with
	// AllowLocalRemote uses the local reader; a nil value without it is a
	// refusal, because no plan can be made without knowing what is published.
	Lister publish.RemoteRefLister
}

Destination describes the repository one synchronization writes into and would publish to.

type DiscoverOptions added in v0.2.0

type DiscoverOptions struct {
	// Config is the decoded, validated profile.
	Config *config.Config
	// LocalGit is the anonymous, no-lazy-fetch runner bound to the local
	// destination repository. It is used for every local object-store
	// operation: ObjectFormat, HasHead, ResolveCommit, state.Load,
	// ObjectInfoBatch, CommitInfo. Because it is anonymous and refuses
	// promisor fetches, no credential can leak to the source host and no
	// command silently downloads objects.
	LocalGit *gitcli.Runner
	// RemoteGit is the credentialed runner used exclusively for network
	// operations: RemoteRefs and FetchExact. It must be bound to the same
	// repository root as LocalGit. A nil value with AllowLocalRemote uses the
	// local reader; a nil value without it is a refusal.
	RemoteGit *gitcli.Runner
	// Remote is the destination push target.
	Remote string
	// Identity is the canonical destination repository.
	Identity string
	// AllowLocalRemote permits a filesystem destination.
	AllowLocalRemote bool
	// Lister reads the refs the destination advertises. A nil value with
	// AllowLocalRemote uses the local reader; a nil value without it is a
	// refusal.
	Lister publish.RemoteRefLister
	// SourceCache is the opened source cache to discover releases from.
	SourceCache *source.Cache
	// StateCommitOverride, when non-empty, is the manual -state-commit flag.
	// It must exactly equal the advertised state OID or it is refused.
	StateCommitOverride string
}

DiscoverOptions configures the preflight discovery that precedes generation.

type Discovery added in v0.2.0

type Discovery struct {
	// Format is the destination's hash algorithm.
	Format gitcli.ObjectFormat
	// Observed is the destination refs at the time of the read, by ref name.
	Observed map[string]string
	// StateCommit is the state record to resume from, empty when the
	// destination holds none.
	StateCommit string
	// State is the loaded state document, zero when StateCommit is empty.
	State state.Document
	// Pending are the upstream releases not yet published, in the semver order
	// DiscoverReleases produced. An empty slice means the destination is
	// already at the fixed point.
	Pending []PendingRelease
	// Adopted is a legacy tag that was verified and adopted into state
	// tracking. It is non-nil only when the firstTag existed on the remote
	// without a state entry and passed all provenance checks. The caller must
	// record it in the outward manifest.
	Adopted *AdoptedTag
	// AdoptedBranch is a legacy branch that state does not record in Published.
	// Non-nil only when state exists but has no Published entry for the
	// configured branch and the branch was verified against cursors. The caller
	// must record it in the outward manifest.
	AdoptedBranch *AdoptedBranch
	// ControlPlaneBranch is a verified operator-only fast-forward layered over
	// the generated commit state records. It does not need state reconciliation:
	// no source image or consumer tag changed.
	ControlPlaneBranch *ControlPlaneBranch
	// ResolvedAnchor records an anchor that was absent from the profile but
	// proved from state and the source cache. Non-nil only when the profile's
	// anchorCommit was empty and state provided a provable anchor.
	ResolvedAnchor *ResolvedAnchor
}

Discovery is the result of the preflight that reads the destination and the source to decide what, if anything, a synchronization should do.

func Discover added in v0.2.0

func Discover(ctx context.Context, opts DiscoverOptions) (*Discovery, error)

Discover reads the destination and the source to decide what a synchronization should do.

It validates the configured remote, identity, and object format; lists the destination refs; validates every advertised ref name, OID format, and namespace; finds and loads the state record; validates the loaded state against the profile; discovers upstream releases; and computes the deterministic ordered set of pending releases by comparing trusted state and advertised destination tags.

Nothing is written. The destination and source are read-only throughout.

func (*Discovery) FixedPoint added in v0.2.0

func (d *Discovery) FixedPoint() bool

FixedPoint reports whether the destination already holds every discovered release and no adoption is pending. A discovery that needs adoption still requires a state-reconciliation plan even though no generation is needed.

type EngineSummary

type EngineSummary struct {
	// Version is the engine build version.
	Version string `json:"version"`
	// Toolchain is the Go toolchain the profile pins for deterministic
	// formatting.
	Toolchain string `json:"toolchain"`
	// ProfileHash is the digest of the output affecting subset of the profile.
	// A change to it re-derives every transformed commit, so it is the field
	// that says whether two synchronizations are comparable at all.
	ProfileHash string `json:"profileHash"`
}

EngineSummary identifies the engine and the profile a run generated under.

type FinalizeOptions added in v0.2.0

type FinalizeOptions struct {
	Config      *config.Config
	Discovery   *Discovery
	SourceCache *source.Cache
	Destination Destination
	Generate    generate.Options
	Release     source.Release
}

FinalizeOptions describes the consumer publication of one completed track.

type Manifest

type Manifest struct {
	// Schema is the manifest version, which must equal ManifestSchema.
	Schema int `json:"schema"`
	// Engine identifies what produced the synchronization.
	Engine EngineSummary `json:"engine"`
	// Source is the upstream release being published.
	Source SourceSummary `json:"source"`
	// Module summarizes what the generation decided.
	Module ModuleSummary `json:"module"`
	// Objects are the destination objects this run wrote. None of them is named
	// by a ref until the publication runs.
	Objects ObjectSummary `json:"objects"`
	// Publish is the exact outward action set, carrying its own hash.
	Publish publish.Manifest `json:"publish"`
	// Hash digests every other field, its own value cleared. It is what an
	// approval names, and it covers the publication manifest as well, so
	// approving a synchronization approves both what was built and where it
	// would go.
	Hash string `json:"hash"`
}

Manifest is everything one synchronization would do, rendered to be compared.

It is the artifact the outward action gate approves, so it is built for comparison rather than for reading once: field order is fixed, every list is sorted and non-nil, and nothing in it depends on where the run happened. Two runs that would publish the same thing produce the same bytes and the same hash, on any machine, from any directory.

It carries no path, no URL other than the canonical destination, no credential, and no environment value. That is not tidiness. The manifest is attached to a review, pasted into an approval, and kept as the record of what was authorized, and a temporary directory from the machine that produced it would break the comparison and leak into the record.

func (Manifest) JSON

func (m Manifest) JSON() ([]byte, error)

JSON renders the manifest as deterministic, indented bytes with a trailing newline.

func (Manifest) Text

func (m Manifest) Text() string

Text renders the manifest for a person, deterministically.

It states the same facts in the same order as the JSON form, so an operator reading the text and a gate comparing the hash are looking at one artifact rather than two renderings that could disagree.

func (Manifest) Verify

func (m Manifest) Verify() error

Verify recomputes the hash and reports a manifest that was modified after it was rendered.

The publication manifest is verified as well, because it carries a hash of its own and a synchronization manifest whose publication half was replaced wholesale would otherwise hash consistently while describing refs nobody planned.

type Module

type Module struct {
	// Files is the complete generated module.
	Files relocate.FileSet
	// Report is what the generation found. Its digests and summaries travel into
	// the manifest, and nothing in it names a path.
	Report generate.Report
}

Module is the generated module a synchronization publishes.

It is the generation's own output rather than a description of it: the files are what gets written, and the report is what the manifest summarizes. Taking both as one value is what lets the destination half of the pipeline run against a module a test composed, without a generation and without the upstream repository a generation needs.

type ModuleSummary

type ModuleSummary struct {
	// Module is the destination module path.
	Module string `json:"module"`
	// ManifestHash digests the complete generated tree: every destination path,
	// its mode, and its content. Two synchronizations that agree on it published
	// the same module.
	ManifestHash string `json:"manifestHash"`
	// Files and Packages are what the tree holds.
	Files    int `json:"files"`
	Packages int `json:"packages"`
	// PrunedFiles and DeniedImports are what the extraction asserted, sorted.
	PrunedFiles   []string `json:"prunedFiles"`
	DeniedImports []string `json:"deniedImports"`
	// PublicAPI are the names the module publishes, sorted. A release that
	// changes them is the one a consumer notices.
	PublicAPI []string `json:"publicApi"`
	// BehaviorChanges are the documented differences from upstream, sorted.
	BehaviorChanges []BehaviorSummary `json:"behaviorChanges"`
	// Dependencies is what the dependency policy decided.
	Dependencies DependencySummary `json:"dependencies"`
	// Notices are the generation's advisory findings, sorted. They did not stop
	// the run, which is exactly why a person approving one should see them.
	Notices []string `json:"notices"`
}

ModuleSummary is what the generation decided, in the terms a reviewer of an outward action reads.

It is a selection rather than the whole generation report. The report answers "is this module correct", runs to thousands of lines, and is written beside the manifest for anyone who wants it. The manifest answers "should this be published", and the fields here are the ones that change that answer: what the module is, what pruning removed, what the public surface became, what behaves differently from upstream, and what the dependency policy decided.

type ObjectSummary

type ObjectSummary struct {
	// Format is the hash algorithm every name is written in.
	Format string `json:"format"`
	// Tree is the generated module's tree.
	Tree string `json:"tree"`
	// Commit is the replayed destination commit for the release.
	Commit string `json:"commit"`
	// Tag is the annotated tag object, and TagTarget the commit it names. They
	// differ from Commit only when the release needed a projection commit of its
	// own, and ProjectionCommit is that commit when it was written.
	Tag              string `json:"tag"`
	TagTarget        string `json:"tagTarget"`
	ProjectionCommit string `json:"projectionCommit"`
	// State names the objects the resumable record was stored as, and
	// StateDigest is the record's own digest.
	StateBlob   string `json:"stateBlob"`
	StateTree   string `json:"stateTree"`
	StateCommit string `json:"stateCommit"`
	StateDigest string `json:"stateDigest"`
}

ObjectSummary names every destination object one synchronization wrote.

Nothing here is reachable. The objects exist in the destination repository and no ref names them, which is what makes a plan free to throw away: the cost of an unpublished synchronization is disk.

type Options

type Options struct {
	// Generate is the generation this synchronization publishes. Its Ref must
	// select a release tag, because a release is what gets published and a
	// branch names none.
	Generate generate.Options
	// Destination is where the objects are written and would be published.
	Destination Destination
	// Bot is the identity every object this run writes records. Empty adopts the
	// profile's configured committer.
	Bot config.Identity
	// BotDate is the raw date the state commit records for both of its roles.
	// Empty adopts the upstream tagger's date, which is the honest default: the
	// release is the only reason the record exists.
	BotDate string
	// StateCommit is the previous state record to resume from, empty for a
	// destination that holds none.
	//
	// It is a commit rather than a ref, so a caller that fetched a record does
	// not have to have published it anywhere. A commit and not a tree: the
	// record this run stores takes it as its parent, which is what makes the
	// state branch a history rather than a series of unrelated roots, and a tree
	// cannot be a parent.
	StateCommit string
}

Options describes one complete synchronization, generation included.

type Outcome

type Outcome struct {
	// Scope is the half of the plan this push carried.
	Scope publish.Scope
	// Attempted names every ref the push carried, populated on a failure where
	// the distinction between attempted and applied is the whole answer.
	Attempted []string
	// Pushed names the refs the destination now holds at the planned object.
	Pushed []string
	// Unapplied names the refs it does not, populated on a failure.
	Unapplied []string
	// NoOps names the refs that already held the planned object.
	NoOps []string
	// DryRun reports that nothing was pushed because the caller rehearsed.
	DryRun bool
	// Verified reports that the destination was read afterwards and its contents
	// are known. When it is false the lists above are unknown rather than empty.
	Verified bool
	// Failed reports a push that did not complete. It is separate from the lists
	// because a push can fail having applied everything, which is what a
	// connection dropping after the remote committed looks like.
	Failed bool
}

Outcome is what one scoped push actually did.

It exists rather than reusing publish.Result because a failed push produces no publish.Result at all: publish reports the failure as a PushError that carries what the destination holds now. Both shapes have to reach the caller as one type, or a caller reading the result would see a nil half and conclude that nothing happened, when what actually happened is the question.

type PendingRelease added in v0.2.0

type PendingRelease struct {
	// Source is the verified upstream release.
	Source source.Release
	// DestinationTag is the tag the release policy maps the source onto.
	DestinationTag string
}

PendingRelease is one upstream release that has not yet been published to the destination.

type ProjectOptions

type ProjectOptions struct {
	// Config is the decoded, validated profile. It decides the destination
	// module and repository, the release policy, the ref layout, and the
	// provenance trailer key.
	Config *config.Config
	// Module is the generated module to publish.
	Module Module
	// Release is the upstream release it was generated from.
	Release Release
	// Destination is where the objects are written and would be published.
	Destination Destination
	// Bot, BotDate, and StateCommit are as they are on Options.
	Bot         config.Identity
	BotDate     string
	StateCommit string
}

ProjectOptions describes the destination half of one synchronization: what to do with a module that has already been generated.

type ReconcileAction added in v0.2.0

type ReconcileAction struct {
	Kind           string `json:"kind"`
	SourceTag      string `json:"sourceTag,omitempty"`
	DestinationTag string `json:"destinationTag,omitempty"`
	PlanHash       string `json:"planHash,omitempty"`
	StateCommit    string `json:"stateCommit,omitempty"`
	Progress       string `json:"progress,omitempty"`
	Done           int    `json:"done,omitempty"`
	Total          int    `json:"total,omitempty"`
	Applied        bool   `json:"applied"`
}

ReconcileAction is one deterministic plan or apply decision.

type ReconcileOptions added in v0.2.0

type ReconcileOptions struct {
	Config      *config.Config
	SourceCache *source.Cache
	LocalGit    *gitcli.Runner
	RemoteGit   *gitcli.Runner
	Destination Destination
	Generate    generate.Options

	StateCommitOverride string
	// Apply and Approval execute exactly one manual reconciliation plan. Automatic
	// ignores them and self-approves each in-memory plan under trusted policy.
	Apply     bool
	Approval  string
	Automatic bool
	Budget    WorkflowBudget
}

ReconcileOptions composes all already-validated runtime boundaries of one trusted workflow. Source acquisition remains anonymous; destination reads and writes use a separate runner.

type ReconcileResult added in v0.2.0

type ReconcileResult struct {
	Schema             int  `json:"schema"`
	FixedPoint         bool `json:"fixedPoint"`
	BudgetExhausted    bool `json:"budgetExhausted"`
	NeedsConfiguration bool `json:"needsConfiguration"`
	// WriteVerified reports that an automatic fixed-point run completed a
	// leased no-op push through the destination credential. No ref moved; the
	// receive-pack handshake proves the token still has write access.
	WriteVerified bool              `json:"writeVerified"`
	Actions       []ReconcileAction `json:"actions"`
}

ReconcileResult is the machine-stable report for one workflow invocation.

func Reconcile added in v0.2.0

func Reconcile(ctx context.Context, opts ReconcileOptions) (*ReconcileResult, error)

Reconcile runs checkpoint steps until the pending release is complete, the workflow budget reserves a clean exit, or a consumer release is published. It publishes at most one consumer release per invocation; the next workflow starts from the newly reconciled branch and processes the next release.

func (ReconcileResult) JSON added in v0.2.0

func (r ReconcileResult) JSON() ([]byte, error)

func (ReconcileResult) Text added in v0.2.0

func (r ReconcileResult) Text() string

type ReconciliationResult added in v0.2.0

type ReconciliationResult struct {
	Document state.Document
	State    state.Record
	Publish  *publish.Plan
	// contains filtered or unexported fields
}

ReconciliationResult is an adoption-only state plan after a consumer push was observed through a completed track.

func PlanAdoptionReconciliation added in v0.2.0

func PlanAdoptionReconciliation(ctx context.Context, opts FinalizeOptions) (*ReconciliationResult, error)

PlanAdoptionReconciliation closes the crash window in which consumer refs landed but their observed-state successor did not.

type Release

type Release struct {
	// Tag is the upstream release tag, such as v1.36.1.
	Tag string
	// Ref is the fully qualified source ref the release was proved against, such
	// as refs/tags/v1.36.1. It is recorded as the state anchor's ref.
	Ref string
	// Commit is the exact upstream commit the release was cut from.
	Commit string
	// Tagger is the upstream tag object's tagger. Its raw date is what the
	// destination tag records, so a regenerated tag is byte identical.
	Tagger gitcli.Signature
	// URL is the upstream release page, published verbatim inside a tag object
	// that can never be taken back.
	URL string
	// Author is the upstream author of Commit, carrying the upstream raw author
	// date. The replayed commit preserves it exactly.
	Author gitcli.Signature
	// CommitterDate is the upstream raw committer date of Commit. The replayed
	// commit records the bot as committer and this date, so a rerun reproduces
	// the object name.
	CommitterDate string
	// Message is the complete upstream commit message, replayed as written and
	// extended with exactly one provenance trailer.
	Message string
}

Release is the upstream release one synchronization publishes.

It is carried rather than looked up, because this package writes into the destination repository and never opens the source one. Plan reads it out of the generation's own source cache and hands it here, which is what keeps the destination side of the pipeline testable against a repository a test built.

type ResolvedAnchor added in v0.2.0

type ResolvedAnchor struct {
	// Commit is the verified anchor commit.
	Commit string
	// Ref is the fully qualified tag ref, such as refs/tags/v1.36.1.
	Ref string
}

ResolvedAnchor records an anchor that was absent from the profile but proved from state and the source cache.

type Result

type Result struct {
	// Manifest is the exact outward action set, hashed. It is the artifact an
	// approval names.
	Manifest Manifest
	// Generation is what the generation produced, nil for a Project call that
	// was handed a module directly.
	Generation *generate.Result
	// Tree is the written generated tree.
	Tree treebuild.Manifest
	// Replay is what the replay produced.
	Replay *replay.Result
	// Release is what the release projection produced.
	Release *release.Result
	// Document is the state record this run would publish, and State names the
	// objects it was stored as.
	Document state.Document
	State    state.Record
	// Publish is the ref plan, which Apply executes and nothing else reads.
	Publish *publish.Plan
	// contains filtered or unexported fields
}

Result is one computed synchronization.

It carries the manifest a person approves and the intermediate results the manifest was built from, so a caller that wants to print what the replay or the release did is reading the same values the manifest summarizes rather than a second rendering of them.

func Plan

func Plan(ctx context.Context, opts Options) (*Result, error)

Plan computes one complete synchronization, generation included, and reports the exact outward actions publishing it would perform.

Nothing is pushed and no ref is created, moved, or deleted. What the run produces is objects that no ref names and a manifest describing which refs would name them, which is a statement about a publication rather than a publication.

The upstream release metadata is read out of the generation's own source cache rather than being asked for, because the two must describe one commit: a caller that stated a tagger date belonging to a different release would produce a tag object that no rerun reproduces, and the only place both facts exist together is the clone the generation just used.

func PlanFinal added in v0.2.0

func PlanFinal(ctx context.Context, opts FinalizeOptions) (*Result, error)

PlanFinal projects the immutable destination tag and returns a normal synchronization Result, so manual apply still approves its exact manifest and trusted apply self-approves that same in-memory hash.

func Project

func Project(ctx context.Context, opts ProjectOptions) (*Result, error)

Project turns an already generated module into the objects a destination repository would hold and the manifest of refs that would name them.

It is exported because it is the half of a synchronization that has nothing to do with upstream. A generation needs a clone of the source project, a Go toolchain, and minutes; everything after it needs a module, a release, and a repository to write into. Keeping the two callable separately is what lets the publication rules be tested against a module a test composed in milliseconds, and it is what a resume of an interrupted run would use.

type SourceSummary

type SourceSummary struct {
	// Tag is the upstream release tag, and Ref the fully qualified source ref it
	// was proved against.
	Tag string `json:"tag"`
	Ref string `json:"ref"`
	// Commit is the exact upstream commit the release was cut from.
	Commit string `json:"commit"`
	// ReleaseTag is the destination tag the release policy maps the upstream tag
	// onto.
	ReleaseTag string `json:"releaseTag"`
}

SourceSummary is the upstream release being published.

The source remote is absent, including when it was overridden. Its value is frequently a path on the machine that ran the generation, and this manifest is compared byte for byte between two runs over different layouts.

type TrustedApplyResult added in v0.2.0

type TrustedApplyResult struct {
	Publication    *ApplyResult
	Reconciliation *publish.Result
	State          state.Record
}

TrustedApplyResult reports the consumer publication and its post-observation state reconciliation separately. A crash between them is recovered by PlanAdoptionReconciliation on the next run.

func ApplyTrusted added in v0.2.0

func ApplyTrusted(ctx context.Context, result *Result) (*TrustedApplyResult, error)

ApplyTrusted self-approves a PlanFinal result, then reconciles the consumer refs it observed after the state-first/consumer-scoped apply.

type WorkflowBudget added in v0.2.0

type WorkflowBudget struct {
	Deadline time.Time
	Reserve  time.Duration
	Now      func() time.Time
}

WorkflowBudget is an operational deadline. It decides whether another chunk starts, never the bytes or object names a started chunk produces.

func (WorkflowBudget) Check added in v0.2.0

func (b WorkflowBudget) Check() error

type WriteVerificationOptions added in v0.2.1

type WriteVerificationOptions struct {
	Config      *config.Config
	LocalGit    *gitcli.Runner
	Destination Destination
}

WriteVerificationOptions describes a trusted no-op destination write probe.

type WriteVerificationResult added in v0.2.1

type WriteVerificationResult struct {
	Schema        int    `json:"schema"`
	Ref           string `json:"ref"`
	Object        string `json:"object"`
	WriteVerified bool   `json:"writeVerified"`
}

WriteVerificationResult is the stable report of a leased no-op branch push.

func VerifyWriteAccess added in v0.2.1

func VerifyWriteAccess(ctx context.Context, opts WriteVerificationOptions) (*WriteVerificationResult, error)

VerifyWriteAccess proves a trusted destination credential can reach receive-pack without discovering or publishing a source release. The branch is pushed to itself with a compare-and-swap lease; every destination ref must remain unchanged.

func (WriteVerificationResult) JSON added in v0.2.1

func (r WriteVerificationResult) JSON() ([]byte, error)

func (WriteVerificationResult) Text added in v0.2.1

Jump to

Keyboard shortcuts

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