pinner

package
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: May 14, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Apply

func Apply(fp *FilePlan)

Apply rewrites the in-memory file lines for every Change in fp. Caller is responsible for persisting via fp.File.Write() afterwards.

Multiple matches on a single line are applied right-to-left to keep byte offsets valid.

func PrintChange

func PrintChange(w io.Writer, c Change)

PrintChange writes a one-line, machine-readable change record to w. Format: `<kind> file=<path> line=<n> action=<a> before=<ref> after=<ref>`.

func RenderChangeTable

func RenderChangeTable(w io.Writer, rows []ChangeRow)

RenderChangeTable writes one table per workflow listing every applied change (Action, Before, After, Latest). The Latest cell is green when After matches Latest and red otherwise (same rule as the default inspection table).

func RenderTable

func RenderTable(w io.Writer, rows []TableRow)

RenderTable writes one table per workflow to w, with the workflow path as a header above each table. Workflow order matches the input row order.

Types

type Change

type Change struct {
	File      string
	LineIndex int
	Kind      Kind

	Action       string // owner/repo[/sub]
	BeforeRef    string
	AfterRef     string
	BeforeSrcRef string // comment ref before
	AfterSrcRef  string // comment ref after ("" = drop comment)
	AfterTail    string // comment tail after (preserved or "")
	// contains filtered or unexported fields
}

Change is one pending rewrite of a single `uses:` directive.

type ChangeRow

type ChangeRow struct {
	Workflow  string
	Action    string
	Before    string
	After     string
	Latest    string
	AfterSHA  string
	LatestSHA string
	LatestErr error
}

ChangeRow describes one applied (or planned, in dry-run) change for the post-mutation summary table.

func BuildChangeRows

func BuildChangeRows(result *Result, res Resolver, concurrency int) ([]ChangeRow, error)

BuildChangeRows builds one row per change in result, fetching the latest release SHA for each unique action via the resolver (deduped through the resolver's singleflight + cache).

type FilePlan

type FilePlan struct {
	File    *workflow.File
	Changes []Change
	Skipped []Skipped
}

FilePlan is the result of planning one workflow file.

type Kind

type Kind string

Kind identifies the rule that produced a change.

const (
	KindPin    Kind = "pin"    // unpinned → SHA, add `# <ref>` comment
	KindUpdate Kind = "update" // already-pinned re-resolved from `# <srcRef>`
	KindLatest Kind = "latest" // pinned → latest tag SHA + latest tag comment, drop comment tail
)

type Mode

type Mode int

Mode controls which subcommand's rules apply when building a plan.

const (
	ModePin    Mode = iota // pin: unpinned → SHA + `# <ref>` comment
	ModeUpdate             // update: pinned → re-resolve via comment (or latest if no comment)
	ModeLatest             // update --latest: pinned → latest tag SHA + latest tag comment, drop comment tail
)

type Resolver

type Resolver interface {
	ResolveRef(owner, repo, ref string) (sha string, err error)
	LatestReleaseSHA(owner, repo string) (sha, srcTag string, err error)
}

Resolver is the surface area the pinner needs from internal/resolver. Defined as an interface so plan logic can be tested with fakes.

type Result

type Result struct {
	Files []*FilePlan
}

Result is the aggregate of all per-file plans.

func Plan

func Plan(paths []string, mode Mode, res Resolver, concurrency int) (*Result, error)

Plan walks each workflow file, classifies every `uses:` match according to `mode`, and resolves SHAs concurrently using `res`. Non-rate-limit resolver errors become Skipped entries; a rate-limit error aborts.

func (*Result) AllChanges

func (r *Result) AllChanges() []Change

AllChanges flattens changes across files in order.

type SkipReason

type SkipReason string

SkipReason explains why an action was skipped. Used for table output and verbose logging.

const (
	SkipAlreadyPinned SkipReason = "already-pinned" // pin: ref is SHA
	SkipNotPinned     SkipReason = "not-pinned"     // update: ref is not SHA
	SkipUnchanged     SkipReason = "unchanged"      // resolved SHA equals existing
	SkipResolveFailed SkipReason = "resolve-failed" // GH API error (non-fatal)
)

type Skipped

type Skipped struct {
	File      string
	LineIndex int
	Action    string
	Ref       string
	Reason    SkipReason
	Err       error
}

Skipped records why a particular match was not converted to a Change.

type TableRow

type TableRow struct {
	Workflow string
	Action   string
	Current  string // ref as written + optional `# srcref` annotation
	Pin      string // SHA the current ref resolves to, or "-"
	Latest   string // SHA of latest release tag, or "-" / error
	// CurrentSHA is the file's literal SHA when the action is already pinned
	// (empty otherwise). Used to color-code the Pin column.
	CurrentSHA string
	// PinSHA / LatestSHA hold the full unformatted SHAs (when known). Used by
	// the renderer to color-code cells without re-parsing strings.
	PinSHA    string
	LatestSHA string
	// LineIndex is the 0-based line in Workflow where this `uses:` lives.
	LineIndex int
	// PinErr / LatestErr carry the underlying resolver errors (nil on success or
	// when the column was not queried). Surfaced to callers for -v output.
	PinErr    error
	LatestErr error
}

TableRow is one row in the inspection table.

func BuildTableRows

func BuildTableRows(paths []string, res Resolver, concurrency int) ([]TableRow, error)

BuildTableRows enumerates every `uses:` match across paths and resolves the "pin" and "latest" columns concurrently. Errors per row become "<err>".

Jump to

Keyboard shortcuts

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