operations.ts

Operations interfaces for dependency injection.

This is the core pattern enabling testability without mocks. All side effects (git, npm, fs, process, build, and the repos binary) are abstracted into interfaces.

Design principles:

  • All operations accept a single options object parameter
  • All fallible operations return Result from @fuzdev/fuz_util
  • Never throw Error in operations - return Result with ok: false
  • Use null for expected "not found" cases (not errors)
  • Include log?: Logger in options where logging is useful

Production usage:

import {default_gitops_operations} from './operations_defaults.ts'; const ops = default_gitops_operations; const result = await ops.git.current_commit_hash({cwd: '/path'}); if (!result.ok) { throw new TaskError(result.message); } const commit = result.value;

Test usage:

import {create_mock_gitops_ops} from './test_helpers.ts'; const ops = create_mock_gitops_ops({ changeset: {has_changesets: async () => ({ok: true, value: false})} }); const result = await publish_repos(repos, {...options, ops}); // Assert on result without any real git/npm calls

See operations_defaults.ts for real implementations, and the test-side mock factories: create_mock_gitops_ops in src/test/test_helpers.ts (plain objects with per-group overrides) and create_fixture_gitops_ops in src/test/fixtures/mock_operations.ts (a fixture's changesets over create_mock_gitops_ops, its fs empty).

view source

Declarations
#

10 declarations

BuildOperations
#

operations.ts view source

BuildOperations import type {BuildOperations} from '@fuzdev/fuz_repos/operations.js';

Build operations for validating packages compile before publishing.

build_package

Builds a package using gro build.

type (options: { repo: LocalRepo; }): Promise<Result<object, { message: string; output?: string | undefined; }>>

options

type { repo: LocalRepo; }
returns Promise<Result>

ChangesetOperations
#

operations.ts view source

ChangesetOperations import type {ChangesetOperations} from '@fuzdev/fuz_repos/operations.js';

Changeset operations for reading and predicting versions from .changeset/*.md files.

has_changesets

Checks if a repo has any changeset files. Returns true if changesets exist, false if none found.

type (options: { repo: LocalRepo; }): Promise<Result<{ value: boolean; }, { message: string; }>>

options

type { repo: LocalRepo; }
returns Promise<Result>

read_changesets

Reads all changeset files from a repo. Returns array of changeset info, or error if reading fails.

type (options: { repo: LocalRepo; log?: Logger | undefined; }): Promise<Result<{ value: ChangesetInfo[]; }, { message: string; }>>

options

type { repo: LocalRepo; log?: Logger | undefined; }
returns Promise<Result>

predict_next_version

Predicts the next version based on changesets. Returns null if no changesets found (expected, not an error). Returns error Result if changesets exist but can't be read/parsed.

type (options: { repo: LocalRepo; log?: Logger | undefined; }): Promise<Result<{ version: string; bump_type: BumpType; }, { message: string; }> | null>

options

type { repo: LocalRepo; log?: Logger | undefined; }
returns Promise<Result | null>

FsOperations
#

operations.ts view source

FsOperations import type {FsOperations} from '@fuzdev/fuz_repos/operations.js';

File system operations for reading and writing files.

Errors are typed via FsError (`not_found | permission_denied | already_exists | io_error) so callers can branch on kind` instead of regex-matching message. See @fuzdev/fuz_util/fs.ts.

readFile

Reads a file from the file system.

type (options: { path: string; encoding: BufferEncoding; }): Promise<Result<{ value: string; }, FsError>>

options

type { path: string; encoding: BufferEncoding; }
returns Promise<Result>

writeFile

Writes a file to the file system.

type (options: { path: string; content: string; }): Promise<Result<object, FsError>>

options

type { path: string; content: string; }
returns Promise<Result>

mkdir

Creates a directory, optionally with recursive creation.

type (options: { path: string; recursive?: boolean | undefined; }): Promise<Result<object, FsError>>

options

type { path: string; recursive?: boolean | undefined; }
returns Promise<Result>

exists

Checks if a path exists on the file system.

type (options: { path: string; }): Promise<boolean>

options

type { path: string; }
returns Promise<boolean>

GitOperations
#

operations.ts view source

GitOperations import type {GitOperations} from '@fuzdev/fuz_repos/operations.js';

Git operations the publishing executor authors with: staging and committing dependency updates and auto-changesets, and reading the commit it published. All operations return Result instead of throwing errors. Where each repo sits (branch, dirt, relation to origin) is ReposOperations's to report.

current_commit_hash

Gets the current commit hash.

type (options?: { cwd?: string | undefined; } | undefined): Promise<Result<{ value: string; }, { message: string; }>>

options?

type { cwd?: string | undefined; }
optional
returns Promise<Result>

add

Stages files for commit.

type (options: { files: string | string[]; cwd?: string | undefined; }): Promise<Result<object, { message: string; }>>

options

type { files: string | string[]; cwd?: string | undefined; }
returns Promise<Result>

commit

Commits files alone (git commit -- <files>), leaving anything else staged out of the commit; files must be non-empty.

type (options: { message: string; files: string[]; cwd?: string | undefined; }): Promise<Result<object, { message: string; }>>

options

type { message: string; files: string[]; cwd?: string | undefined; }
returns Promise<Result>

GitopsOperations
#

operations.ts view source

GitopsOperations import type {GitopsOperations} from '@fuzdev/fuz_repos/operations.js';

Combined operations interface grouping all gitops functionality. This is the main interface injected into publishing and validation workflows.

changeset

type ChangesetOperations

git

type GitOperations

process

type ProcessOperations

npm

type NpmOperations

preflight

type PreflightOperations

fs

type FsOperations

build

type BuildOperations

repos

repos status, for the executor's re-check of each repo right before its publish.

type ReposOperations

NpmOperations
#

operations.ts view source

NpmOperations import type {NpmOperations} from '@fuzdev/fuz_repos/operations.js';

NPM registry operations for package availability checks and authentication. Includes exponential backoff for waiting on package propagation.

wait_for_package

Waits for a package version to be available on NPM. Uses exponential backoff with configurable timeout.

type (options: { pkg: string; version: string; wait_options?: WaitOptions | undefined; log?: Logger | undefined; }): Promise<Result<object, { message: string; }>>

options

type { pkg: string; version: string; wait_options?: WaitOptions | undefined; log?: Logger | undefined; }
returns Promise<Result>

check_auth

Checks npm authentication status.

type (): Promise<Result<{ username: string; }, { message: string; }>>

returns Promise<Result>

check_registry

Checks if npm registry is reachable.

type (): Promise<Result<object, { message: string; }>>

returns Promise<Result>

PreflightOperations
#

operations.ts view source

PreflightOperations import type {PreflightOperations} from '@fuzdev/fuz_repos/operations.js';

Preflight validation operations run before publishing: building every package the plan publishes, and npm authentication. Repo git state is the readiness gate's, before preflight (see repo_readiness.ts).

run_preflight_checks

Runs preflight validation checks before publishing.

type (options: RunPreflightChecksOptions): Promise<PreflightResult>

options

returns Promise<PreflightResult>

ProcessOperations
#

operations.ts view source

ProcessOperations import type {ProcessOperations} from '@fuzdev/fuz_repos/operations.js';

Process operations for the commands the publishing executor runs in a repo (gro publish, gro deploy).

run_interactive

Runs a command in the foreground and waits for it to exit: stdin is the terminal's, so a prompt (npm's 2FA one-time password) can be answered, and the child's output shows live — its stdout on ours, or on our stderr when stdout says so, and its stderr on ours. A failure carries the end of what the child wrote to stderr, bounded in lines and characters.

type (options: { cmd: string; args: string[]; cwd?: string | undefined; stdout?: "stdout" | "stderr" | undefined; }): Promise<Result<object, { message: string; stderr_tail?: string | undefined; }>>

options

type { cmd: string; args: string[]; cwd?: string | undefined; stdout?: "stdout" | "stderr" | undefined; }
returns Promise<Result>

ReposCommandOutput
#

operations.ts view source

ReposCommandOutput import type {ReposCommandOutput} from '@fuzdev/fuz_repos/operations.js';

What a repos command printed and how it exited, unparsed.

stdout

type string

stderr

type string

exit_code

0 for a report, 2 for an error document, 1 for a fatal I/O error (maybe no JSON).

type number

ReposOperations
#

operations.ts view source

ReposOperations import type {ReposOperations} from '@fuzdev/fuz_repos/operations.js';

Operations running the Rust repos binary, which owns fleet git state. Parsing its output is repos_status_load.ts's, not the runner's.

status

Runs repos [--registry <path>] status [--fetch] <keys…> --json in the process's cwd and returns what it printed, whatever its exit code. With fetch, repos fetches each entry from origin first, which writes remote-tracking refs and nothing else. Fails only when the binary didn't run to an exit: not_found when it isn't on PATH.

type (options: { keys: string[]; registry?: string | undefined; fetch?: boolean | undefined; }): Promise<Result<{ output: ReposCommandOutput; }, { kind: "failed" | "not_found"; message: string; }>>

options

type { keys: string[]; registry?: string | undefined; fetch?: boolean | undefined; }
returns Promise<Result>

Depends on
#

Imported by
#