npmrelease

package
v0.95.6 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package npmrelease coordinates an approved npm publication workflow without ever handling npm credentials. The repository owns the GitHub Actions workflow; WB dispatches it, records the exact run/head receipt, verifies the requested package version in the npm registry, and returns release events for the shared dependency-wave engine.

Index

Constants

View Source
const (
	SchemaVersion          = 3
	StatusPlanned          = "planned"
	StatusRunning          = "running"
	StatusPublished        = "published"
	StatusDispatchUnknown  = "dispatch_unknown"
	StatusDispatchFailed   = "dispatch_failed"
	StatusAwaitingRun      = "awaiting_run"
	StatusAwaitingRegistry = "awaiting_registry"
	StatusFailed           = "failed"
)

Variables

This section is empty.

Functions

func EventsFor

func EventsFor(report Report) ([]deps.ReleaseEvent, error)

EventsFor returns only registry-confirmed events. A caller must not hand planned or failed receipts to deps bump.

func IsSecretLikeWorkflowInputKey

func IsSecretLikeWorkflowInputKey(key string) bool

IsSecretLikeWorkflowInputKey recognizes names that might carry a credential in a workflow_dispatch field. Callers must reject these before a release is normalized, persisted, or rendered into subprocess arguments.

func OperationIDFor

func OperationIDFor(releases []Release) string

OperationIDFor returns a deterministic operation name for the publication identity: repository/workflow/package/version/ref only. Workflow inputs are deliberately excluded so every request to publish the same version shares one operation lock and default report directory. Resume performs the stricter input-fingerprinted releaseIdentity comparison separately.

func PublicationClaimOperationIDs

func PublicationClaimOperationIDs(releases []Release) []string

PublicationClaimOperationIDs returns deterministic, package-version claim lock names for already-normalized releases. Unlike a campaign operation, a claim deliberately ignores workflow inputs, repository, workflow, ref, and neighboring tuples: npm can publish one exact package version only once, so overlapping subset/superset campaigns must serialize that publication.

func ReportExists

func ReportExists(directory string) (bool, error)

ReportExists recognizes either durable representation. A JSON-only remnant is intentionally treated as existing (and therefore refuses a fresh apply) rather than silently allowing a duplicate workflow dispatch.

func ValidateOptions

func ValidateOptions(options Options) error

ValidateOptions performs every no-I/O publication option check. Command handlers use it before fleet discovery or a workflow dispatch, and Run uses it again so package callers get the same boundary.

func ValidateRelease

func ValidateRelease(release Release) error

ValidateRelease checks all explicit user-controlled identifiers before any command is run. Workflow names are limited to repository-owned workflow files, rather than arbitrary shell fragments or a hidden remote action.

func WriteReport

func WriteReport(directory string, report Report) error

WriteReport persists the resumable report. Both canonical YAML and JSON are independently atomically replaced so a crash cannot expose a half-written document to a resume or machine reader. It is intentionally separate from stdout formatting so failure paths keep the same durable receipt.

Types

type CommandResult

type CommandResult struct {
	Output string
	Code   int
	Err    error
}

CommandResult is the small subprocess seam used by tests and by the real GitHub/npm command runner. Code and Output are retained separately so a non-zero gh status can still carry a useful JSON receipt.

type CommandRunner

type CommandRunner interface {
	Run(context.Context, string, ...string) CommandResult
}

CommandRunner executes an external command. It must use the caller's existing gh/npm credential helpers; WB never accepts or constructs tokens.

type OSCommandRunner

type OSCommandRunner struct{}

func (OSCommandRunner) Run

func (OSCommandRunner) Run(ctx context.Context, dir string, args ...string) CommandResult

type Options

type Options struct {
	Apply        bool
	DryRun       bool
	Resume       bool
	Ref          string
	Timeout      time.Duration
	PollInterval time.Duration
	Registry     string
	ReportDir    string
	Runner       CommandRunner
	Now          func() time.Time
	Persist      func(Report) error
	Previous     *Report
	Progress     progress.Reporter
	// contains filtered or unexported fields
}

Options controls publication safety and polling. Apply is the only option that permits workflow dispatch; dry-run never contacts GitHub or npm.

type Receipt

type Receipt struct {
	Release
	Status     string    `json:"status" yaml:"status"`
	Reason     string    `json:"reason,omitempty" yaml:"reason,omitempty"`
	DispatchAt time.Time `json:"dispatch_at,omitempty" yaml:"dispatch_at,omitempty"`
	HeadSHA    string    `json:"head_sha,omitempty" yaml:"head_sha,omitempty"`
	// DispatchBaselineAt and DispatchBaselineRunIDs are captured before the
	// workflow_dispatch request. They are the primary identity fence for a
	// resume: only an exact-head run absent from this set can be the run WB
	// dispatched. A timestamp is retained solely as a bounded secondary check
	// against a delayed, pre-existing run that was absent from GitHub's list.
	DispatchBaselineAt     time.Time `json:"dispatch_baseline_at,omitempty" yaml:"dispatch_baseline_at,omitempty"`
	DispatchBaselineRunIDs []string  `json:"dispatch_baseline_run_ids,omitempty" yaml:"dispatch_baseline_run_ids,omitempty"`
	RunID                  string    `json:"run_id,omitempty" yaml:"run_id,omitempty"`
	RunURL                 string    `json:"run_url,omitempty" yaml:"run_url,omitempty"`
	RunHeadSHA             string    `json:"run_head_sha,omitempty" yaml:"run_head_sha,omitempty"`
	RunStatus              string    `json:"run_status,omitempty" yaml:"run_status,omitempty"`
	RunConclusion          string    `json:"run_conclusion,omitempty" yaml:"run_conclusion,omitempty"`
	RunCreatedAt           time.Time `json:"run_created_at,omitempty" yaml:"run_created_at,omitempty"`
	RunCompletedAt         time.Time `json:"run_completed_at,omitempty" yaml:"run_completed_at,omitempty"`
	RegistryVersion        string    `json:"registry_version,omitempty" yaml:"registry_version,omitempty"`
	RegistryURL            string    `json:"registry_url,omitempty" yaml:"registry_url,omitempty"`
	RegistryCheckedAt      time.Time `json:"registry_checked_at,omitempty" yaml:"registry_checked_at,omitempty"`
}

Receipt is the durable evidence for one workflow publication. A receipt is retained when a later registry check or dependency wave fails so --resume never dispatches an already accepted workflow again.

type Release

type Release struct {
	Repository       string `json:"repository" yaml:"repository"`
	Workflow         string `json:"workflow" yaml:"workflow"`
	Package          string `json:"package" yaml:"package"`
	Version          string `json:"version" yaml:"version"`
	Ref              string `json:"ref" yaml:"ref"`
	InputFingerprint string `json:"input_fingerprint,omitempty" yaml:"input_fingerprint,omitempty"`
	// Inputs are deliberately process-local. Even safe-looking workflow field
	// values can carry a credential by mistake, so reports and stdout retain
	// only InputFingerprint for resume identity and never serialize raw values.
	Inputs map[string]string `json:"-" yaml:"-"`
}

Release is one explicit provider/workflow/package/version tuple. Keeping the tuple intact prevents a multi-package provider campaign from silently pairing the wrong workflow with a package.

func Normalize

func Normalize(releases []Release, ref string) ([]Release, error)

Normalize validates, fills defaults, copies inputs, and rejects duplicate package/version tuples. Duplicate inputs are unsafe because they could dispatch the same release workflow twice.

type Report

type Report struct {
	SchemaVersion        int                 `json:"schema_version" yaml:"schema_version"`
	Operation            string              `json:"operation" yaml:"operation"`
	Generation           string              `json:"generation,omitempty" yaml:"generation,omitempty"`
	Status               string              `json:"status" yaml:"status"`
	Ref                  string              `json:"ref" yaml:"ref"`
	Releases             []Receipt           `json:"releases" yaml:"releases"`
	Events               []deps.ReleaseEvent `json:"events,omitempty" yaml:"events,omitempty"`
	PropagationOperation string              `json:"propagation_operation,omitempty" yaml:"propagation_operation,omitempty"`
	// Propagation is the same persisted BumpReport the regular `wb deps bump
	// npm` engine produces. Keeping it here makes the publication receipt
	// independently resumable and machine-readable without a parallel wave
	// orchestration format.
	Propagation *deps.BumpReport `json:"propagation,omitempty" yaml:"propagation,omitempty"`
}

Report is persisted before any external action and after every state transition. It is intentionally independent of deps.BumpReport: release evidence can be resumed even if the downstream wave has not started.

func LoadReport

func LoadReport(directory string) (Report, error)

LoadReport loads the canonical YAML resume artifact.

func Run

func Run(ctx context.Context, releases []Release, options Options) (Report, error)

Run executes the publication phase. If Apply is false it returns a deterministic planned report without invoking gh or npm. If Apply is true, every receipt is persisted before dispatch and after each external state transition. Resume reuses all receipts and never dispatches a tuple already carrying a dispatch timestamp or run identity.

func (Report) JSON

func (report Report) JSON() ([]byte, error)

func (Report) WithGeneration

func (report Report) WithGeneration() Report

JSON and YAML are intentionally exposed by the package so command handlers and integration tests use the same field names and deterministic encoding. Both carry one logical generation, allowing --resume to fail closed if a crash happens between their individual atomic renames.

func (Report) YAML

func (report Report) YAML() ([]byte, error)

Jump to

Keyboard shortcuts

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