depupdate

package
v0.10.0 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package depupdate provides direct dependency update functionality that bypasses the Smith AI worker. It reuses depcheck scanners to discover outdated packages, groups them, applies updates via package-manager commands, verifies them with Temper, and wires changelog generation + PR creation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckoutUpdateBranch

func CheckoutUpdateBranch(ctx context.Context, anvilPath string) (string, error)

CheckoutUpdateBranch creates or checks out the batch-update branch for the current date (deps/batch-update-<YYYY-MM-DD>) in the given anvil directory. The branch is based on origin's default branch so that the diff never includes unrelated changes from a feature branch or detached HEAD. If the branch already exists locally it is checked out. If it exists only on the remote it is fetched and tracked. Returns the branch name and an error if the branch cannot be created or checked out.

func CloseMatchingDepBeads

func CloseMatchingDepBeads(ctx context.Context, anvilPath string, groups []UpdateGroup) error

CloseMatchingDepBeads closes any open depcheck beads whose title references a package covered by one of the provided UpdateGroups. It is called after CreatePR returns successfully so that stale "Deps(<eco>): update <pkg> …" beads are removed from the queue instead of accumulating as resolved work.

func CommitGroup

func CommitGroup(ctx context.Context, anvilPath string, group UpdateGroup) error

CommitGroup stages all changes and creates a commit for the successfully installed group. The commit message follows the conventional format: "chore(deps): update <group-name> (<kind>)".

func CreatePR

func CreatePR(ctx context.Context, anvilPath, anvilName, branch string, groups []UpdateGroup) (string, error)

CreatePR pushes the given branch to origin and opens a single pull request summarising all updated groups for the given anvil. The branch must have already been created and checked out by CheckoutUpdateBranch. Returns the PR URL reported by gh, or an error if any step fails.

func DetectBilingual

func DetectBilingual(anvilPath string) bool

DetectBilingual reports whether the changelog.d/ directory in anvilPath contains bilingual fragments (files ending in .en.md or .nb.md). This mirrors the convention used by other projects that maintain separate English and Norwegian changelog files.

func FormatSummaryLine

func FormatSummaryLine(results []AnvilResult, opts Options) string

FormatSummaryLine returns a one-line summary like "12 outdated dependencies across 3 anvils".

func GenerateChangelog

func GenerateChangelog(anvilPath string, groups []UpdateGroup, isBilingual bool) error

GenerateChangelog writes one or two changelog fragment files for the given set of dependency update groups into <anvilPath>/changelog.d/, then git-adds and commits them.

Fragment naming:

  • Monolingual: deps-batch-<YYYY-MM-DD-HHmmss>.md
  • Bilingual: deps-batch-<YYYY-MM-DD-HHmmss>.en.md (English) deps-batch-<YYYY-MM-DD-HHmmss>.nb.md (Norwegian — same content)

The timestamp suffix makes each invocation collision-safe so that multiple runs on the same day do not overwrite each other.

The isBilingual flag can be set explicitly by the caller, or the caller can use DetectBilingual to derive it from the existing changelog directory.

func InstallDotnetGroup

func InstallDotnetGroup(ctx context.Context, projectDir string, group UpdateGroup) error

InstallDotnetGroup runs `dotnet add <csproj> package <name> -v <version>` for each package in the group. It searches the project directory for the .csproj file that contains a PackageReference for each package.

func InstallGoGroup

func InstallGoGroup(ctx context.Context, moduleDir string, group UpdateGroup) error

InstallGoGroup runs `go get pkg1@v1 pkg2@v2 ...` followed by `go mod tidy` in the given module directory. Returns an error if either command fails.

func InstallNpmGroup

func InstallNpmGroup(ctx context.Context, projectDir string, group UpdateGroup) error

InstallNpmGroup runs `npm install pkg1@v1 pkg2@v2 ...` with all packages in the group at once. Returns an error if the install fails (peer dep conflict, network error, etc.).

If group.SourceDir is set, npm install runs there (the directory containing the relevant package.json). Otherwise projectDir (the anvil root) is used as a fallback.

func PrintSummary

func PrintSummary(w io.Writer, results []AnvilResult, opts Options) int

PrintSummary writes a human-readable summary of outdated dependencies to w. Returns the total number of updates displayed.

func RollbackGroup

func RollbackGroup(_ context.Context, anvilPath string, group UpdateGroup, reason error) error

RollbackGroup discards all uncommitted changes in the anvil directory by running `git reset --hard` (resets both index and working tree) followed by `git clean -fdx` (removes untracked files including ignored artifacts such as node_modules/, bin/, obj/). It logs which group failed and why. Uses a fresh context with a 30-second timeout so that rollback still succeeds even when the caller's context has been cancelled.

func VerifyGroup

func VerifyGroup(ctx context.Context, anvilPath string, anvilConfig config.AnvilConfig) (*temper.Result, error)

VerifyGroup runs temper (build + lint + test) against the anvil to confirm that the group's updates haven't broken anything. Returns the temper result so the caller can decide to commit or rollback.

Types

type Anvil

type Anvil struct {
	// Name is the anvil's logical identifier (used in display and logging).
	Name string
	// Path is the absolute filesystem path to the repository root.
	Path string
	// Config carries per-anvil settings (temper flags, race detection, etc.).
	Config config.AnvilConfig
	// DB is used for event logging during scans. May be nil to disable logging.
	DB *state.DB
	// Timeout is the per-anvil scan timeout. Zero defaults to 5 minutes.
	Timeout time.Duration
}

Anvil describes a repository workspace for dependency scanning and updates.

type AnvilReport

type AnvilReport struct {
	// Anvil is the source descriptor used when scanning.
	Anvil Anvil
	// Groups holds the update groups ready for Apply or Preview.
	Groups []UpdateGroup
	// Errors contains per-ecosystem scan errors (ecosystem name → error).
	// A nil map means all ecosystems scanned successfully.
	Errors map[string]error
}

AnvilReport summarizes the available updates and pre-grouped changes for one anvil. Returned by Scan so callers (Hearth, Ledger) can display or apply updates without going through the CLI.

func Scan

func Scan(ctx context.Context, anvils []Anvil, opts Options) ([]AnvilReport, error)

Scan runs dependency checks across the given anvils and returns per-anvil reports with updates pre-grouped for display or application. Per-anvil scan failures are captured in AnvilReport.Errors rather than aborting the whole scan, so callers always receive a report for every requested anvil.

This function provides the programmatic equivalent of `forge update-deps` without the interactive CLI layer, allowing Hearth and Ledger to query available updates directly.

type AnvilResult

type AnvilResult struct {
	Anvil      string
	Path       string
	Ecosystems []*depcheck.CheckResult
}

AnvilResult holds scan results for a single anvil, potentially spanning multiple ecosystems (Go, npm, NuGet).

func (*AnvilResult) TotalUpdates

func (ar *AnvilResult) TotalUpdates(opts Options) int

TotalUpdates returns the total number of outdated dependencies across all ecosystems for this anvil, respecting the given filter options.

type Options

type Options struct {
	// PatchOnly limits results to patch-level updates only.
	PatchOnly bool
	// NoMajor excludes major version updates from results.
	NoMajor bool
}

Options controls which updates are included in a scan.

type Result

type Result struct {
	// Group is the UpdateGroup that was processed.
	Group UpdateGroup
	// Applied is true when the group was installed, verified, and committed.
	Applied bool
	// Err holds the error that caused the group to be skipped or rolled back.
	// Nil when Applied is true.
	Err error
}

Result records the outcome of applying a single UpdateGroup.

func Apply

func Apply(ctx context.Context, anvilPath string, anvilCfg config.AnvilConfig, groups []UpdateGroup) ([]Result, error)

Apply executes the given groups against the specified anvil by installing packages, verifying with Temper (build + lint + test), and committing on success or rolling back on failure. It returns one Result per input group.

This function provides the programmatic equivalent of the apply phase in `forge update-deps --create-pr`, without the branch/PR/changelog steps. Callers (Hearth, Ledger) can wrap it with their own PR and changelog logic.

func Preview

func Preview(groups []UpdateGroup) []Result

Preview returns a Result slice describing what Apply would do for the given groups without making any changes to disk or running any package-manager commands. It is the dry-run variant used by Hearth's overlay preview so users can inspect pending updates before confirming application.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner orchestrates dependency scanning across anvils using the existing depcheck scanners. Future sub-tasks will add update execution, grouping, and PR creation methods.

func NewRunner

func NewRunner(db *state.DB, anvilPaths map[string]string, cfg *config.SettingsConfig) *Runner

NewRunner creates a Runner that uses the provided depcheck Scanner for discovering outdated dependencies.

func (*Runner) Scan

func (r *Runner) Scan(ctx context.Context, anvilPaths map[string]string) []AnvilResult

Scan runs dependency checks on all configured anvils and returns the aggregated results. Every anvil is included in the output so that callers can distinguish "no supported ecosystems" from "no updates" from "scan error".

type UpdateGroup

type UpdateGroup struct {
	Name      string                  // e.g. "vite ecosystem", "@tailwindcss packages", "lodash"
	Updates   []depcheck.ModuleUpdate // packages in this group
	Kind      string                  // worst-case kind: "major" > "minor" > "patch"
	Ecosystem string                  // e.g. "Go", "npm", "NuGet"
	SourceDir string                  // directory containing the manifest (e.g. package.json); empty means repo root
}

UpdateGroup represents a set of related package updates that should be installed together atomically.

func ExecuteGroups

func ExecuteGroups(ctx context.Context, anvilPath string, anvilCfg config.AnvilConfig, groups []UpdateGroup) []UpdateGroup

ExecuteGroups applies each UpdateGroup to the given anvil by installing packages, running Temper verification, and committing on success or rolling back on failure. It returns the subset of groups that were successfully applied and committed.

func FilterGroups

func FilterGroups(groups []UpdateGroup, opts Options) []UpdateGroup

FilterGroups returns only the groups whose Kind is allowed by opts. Groups whose kind is excluded by PatchOnly or NoMajor are dropped.

func GroupUpdates

func GroupUpdates(ctx context.Context, results []*depcheck.CheckResult) []UpdateGroup

GroupUpdates takes scan results for a single anvil and groups related packages so they can be installed atomically.

Grouping strategies are applied in order:

  1. Peer dep groups (npm only) — packages sharing peer dependencies
  2. Scope groups — packages sharing an npm scope (@scope/*)
  3. Standalone — each remaining package becomes its own group

func SelectGroups

func SelectGroups(r io.Reader, w io.Writer, groups []UpdateGroup, yesAll bool) []UpdateGroup

SelectGroups presents each UpdateGroup to the user and collects a yes/no response. When yesAll is true every group is accepted without prompting. The function reads responses from r and writes prompts to w.

Jump to

Keyboard shortcuts

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