@capgo/cli
Version:
A CLI to upload to capgo servers
88 lines (87 loc) • 4.45 kB
TypeScript
import type { BuildCredentials } from '../../schemas/build.js';
export type CiSecretProvider = 'github' | 'gitlab';
export interface CiSecretEntry {
key: string;
value: string;
masked: boolean;
}
export interface CiSecretTarget {
provider: CiSecretProvider;
label: string;
cli: 'gh' | 'glab';
}
export interface CiSecretDiscovery {
targets: CiSecretTarget[];
setup: CiSecretSetupAdvice[];
notes: string[];
}
export interface CiSecretSetupAdvice {
target: CiSecretTarget;
reason: 'not-installed' | 'not-authenticated';
message: string;
commands: string[];
}
interface CommandRunOptions {
input?: string;
}
export interface CommandRunResult {
status: number | null;
stdout: string;
stderr: string;
error?: Error;
}
export type CommandRunner = (command: string, args: string[], options?: CommandRunOptions) => CommandRunResult;
/**
* Async runner. Used by the wizard so spawned `gh` / `glab` calls don't block
* the Node event loop — without this, `ink-spinner`'s animation freezes for
* the entire duration of every shell-out, which feels like the wizard has hung.
*
* Tests can pass either a sync (CommandRunner) or async runner — every helper
* that calls runner.* does so via `await` so a sync runner returning a plain
* result still works (Promise.resolve coerces it).
*/
export type AsyncCommandRunner = (command: string, args: string[], options?: CommandRunOptions) => CommandRunResult | Promise<CommandRunResult>;
export declare function runCommand(command: string, args: string[], options?: CommandRunOptions): CommandRunResult;
/**
* Non-blocking shell-out. Mirrors `runCommand`'s shape but uses `spawn` so
* the Node event loop is free to tick spinners and process input while gh /
* glab work. Default for any wizard-side helper that needs to render UI
* during the call.
*/
export declare function runCommandAsync(command: string, args: string[], options?: CommandRunOptions): Promise<CommandRunResult>;
export declare function createCiSecretEntries(credentials: Partial<BuildCredentials>, apiKey?: string): CiSecretEntry[];
export declare function detectCiSecretTargets(runner?: CommandRunner): CiSecretDiscovery;
export declare function getCiSecretTargetLabel(target: CiSecretTarget | null | undefined): string;
/**
* Resolve the concrete `owner/repo` (GitHub) or `group/project` (GitLab) the
* `gh` / `glab` CLI will target from the current working directory.
*
* Returns null when the CLI can't determine the repo (e.g. cwd is not a git
* repo, multiple remotes with no `gh-resolved` config, auth scopes missing).
*
* The wizard MUST show this string to the user and require explicit
* confirmation before any `gh secret set` / `glab variable set` runs — those
* commands silently overwrite without backup, so the user has to know which
* repo they're about to mutate.
*/
export declare function getCiSecretRepoLabel(target: CiSecretTarget, runner?: CommandRunner): string | null;
/**
* Non-blocking variant of `getCiSecretRepoLabel`. Identical logic, but
* `await`s the runner so the event loop can tick during the gh/glab call —
* lets Ink spinners actually animate during the resolution.
*/
export declare function getCiSecretRepoLabelAsync(target: CiSecretTarget, runner?: AsyncCommandRunner): Promise<string | null>;
export declare function listExistingCiSecretKeys(target: CiSecretTarget, keys: string[], runner?: CommandRunner): string[];
/** Non-blocking variant of `listExistingCiSecretKeys`. */
export declare function listExistingCiSecretKeysAsync(target: CiSecretTarget, keys: string[], runner?: AsyncCommandRunner): Promise<string[]>;
export declare function uploadCiSecrets(target: CiSecretTarget, entries: CiSecretEntry[], existingKeys?: string[], runner?: CommandRunner): void;
/**
* Non-blocking variant of `uploadCiSecrets`. Calls `onProgress(current, total,
* keyName)` before every `gh secret set` / `glab variable set` so the wizard
* can render "Pushing N of M: <KEY>…" instead of a frozen spinner.
*
* Pushes are still sequential — gh/glab don't have a bulk-set API, and
* parallelising would risk rate limits + makes failure semantics ambiguous.
*/
export declare function uploadCiSecretsAsync(target: CiSecretTarget, entries: CiSecretEntry[], existingKeys?: string[], runner?: AsyncCommandRunner, onProgress?: (current: number, total: number, keyName: string) => void): Promise<void>;
export {};