pusher

package
v0.2.0-dev.1 Latest Latest
Warning

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

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

README

Pusher

Pluggable abstraction for landing the changes of one or more batches onto a target branch and pushing the result to a source-control remote.

Interface

Pusher exposes a single Push method that accepts an ordered list of batches and resolves each batch's changes itself through an injected changeset resolver. Implementations are bound to a specific (checkout, remote, target) tuple at construction time, so the interface itself stays vendor- and configuration-agnostic. The batch list designs for a merge-train (landing several ready batches in one atomic push); today the merge stage passes a single batch.

The interface enforces an all-or-nothing atomicity contract: when Push returns an error, no change has reached the remote — neither partially nor fully. Callers can treat a non-nil error as "the remote is exactly as it was before the call". The ErrConflict sentinel marks user-caused failures so callers can route them to a non-retry path.

A successful Push returns one entity.BatchOutcome per input batch, in input order, each carrying one entity.ChangeOutcome per change in that batch. Each change outcome reports either:

  • entity.OutcomeStatusCommitted with the list of CommitSHAs produced on the target branch (one change can land as multiple commits, e.g. a stack of PRs); or
  • entity.OutcomeStatusAlreadyExisted with no commits, when the change is already present on the target branch (previously landed via another path, or subsumed by an earlier change in the same push). Git surfaces this as "rebased out" during a cherry-pick.

There is no per-batch status: the push is all-or-nothing across the whole call, so a per-batch pass/fail would be uniformly redundant.

Implementations

  • git/ — applies changes against a local checkout via git cherry-pick, then git push. Construction takes the path to the checkout, the remote name, and the target branch; the implementation owns that working tree and serializes concurrent invocations.
  • fake/ — test/example stub. Reports every change as committed unless a change URI carries a failure marker (sq-fake=conflictErrConflict, sq-fake=push-error → error), letting a single running stack exercise negative paths from request payloads. Not for production.

Adding a new backend

  1. Create extension/pusher/{backend}/ with a Pusher implementation.
  2. Bind the implementation to its checkout/remote/target at construction.
  3. Resolve each batch's changes via the injected resolver, then map each entity.Change to the backend's commit/push primitives.
  4. Honour the atomicity contract: never publish partial state. Return ErrConflict (wrapped) for user-caused apply failures and a plain error for transient infra failures.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrConflict = errors.New("change conflict")

ErrConflict is returned by a Pusher when one of the changes fails to apply cleanly on top of the current tip of the target branch. Callers should treat conflicts as user-caused and non-retryable.

Functions

This section is empty.

Types

type Config

type Config struct {
	// QueueName identifies the queue this Pusher serves.
	QueueName string
}

Config carries the per-queue identity handed to a Factory. The system knows only the queue name; everything an implementation needs (checkout, remote, target) is injected at construction by the integrator.

type Factory

type Factory interface {
	// For returns the Pusher for the given queue.
	For(cfg Config) (Pusher, error)
}

Factory builds the Pusher for a queue. Implementations are provided by integrators (and tests) and inject whatever they need at construction.

type Pusher

type Pusher interface {
	// Push resolves and applies the changes of the given batches, in order,
	// onto the target branch and pushes the resulting commits. The batch list
	// designs for a merge-train (land several ready batches in one atomic push);
	// today merge passes a single batch. See the type-level docs for the
	// atomicity contract.
	Push(ctx context.Context, batches []entity.Batch) (entity.PushResult, error)
}

Pusher applies the changes of one or more batches on top of a target branch and pushes the result to the source-control remote. Each implementation is bound to a specific (checkout, remote, target) at construction time and resolves each batch's changes itself through an injected changeset resolver.

Atomicity contract: when Push returns a non-nil error, NO change has been pushed to the remote — neither partially nor fully. Implementations must either roll back any local state or arrange for the push to never happen when any change fails to apply. Callers can treat a non-nil error as "the remote is exactly as it was before the call".

On success, len(entity.PushResult.Batches) == len(batches) and Batches[i] describes what happened to batches[i], with one entity.ChangeOutcome per change in that batch in apply order. A change can produce multiple commits (entity.OutcomeStatusCommitted, CommitSHAs populated in apply order) or none at all (entity.OutcomeStatusAlreadyExisted, CommitSHAs empty) — the latter happens when the change's content is already present on the target branch.

Directories

Path Synopsis
Package fake provides a pusher.Pusher whose outcome is driven by the input changes.
Package fake provides a pusher.Pusher whose outcome is driven by the input changes.
Package git is a simple Pusher implementation backed by a local git checkout.
Package git is a simple Pusher implementation backed by a local git checkout.
Package mock is a generated GoMock package.
Package mock is a generated GoMock package.

Jump to

Keyboard shortcuts

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