cog
06ec2978 - feat: registry-agnostic provider system for multi-registry support (#2668)

Commit
8 days ago
feat: registry-agnostic provider system for multi-registry support (#2668) * feat(provider): add Provider interface definition * feat(provider): add GenericProvider for OCI registries * feat(provider): add ReplicateProvider for r8.im registry Implements the Provider interface for Replicate's r8.im registry: - MatchesRegistry() checks for r8.im and global registry host - Login() implements the browser-based token flow (extracted from cli/login.go) - LoginWithOptions() provides configurable token-stdin support - PrePush/PostPush are no-ops for now (analytics still in push.go) This extracts the Replicate-specific login logic into the provider abstraction, making it reusable and testable independently. * feat(provider): add Registry for provider lookup and setup Adds provider registry functionality: - Registry type with ForImage() and ForHost() methods for provider lookup - ExtractHost() to parse registry host from image names (handles ports, tags, digests) - DefaultRegistry() singleton for global access - setup.Init() to initialize default registry with Replicate and Generic providers Provider order: Replicate (specific) -> Generic (fallback for any OCI registry) * refactor(cli): use provider system for cog login Refactors the login command to use the provider abstraction: - Initializes provider registry with setup.Init() - Looks up provider by registry host - Replicate provider handles its own token-based auth flow - Generic provider returns ErrUseDockerLogin with helpful message The Replicate-specific login logic (token verification, browser flow) now lives in pkg/provider/replicate/replicate.go, making login.go a thin dispatcher that delegates to the appropriate provider. Also exports LoginToRegistry() for programmatic use by other commands. * refactor(cli): integrate provider system into cog push Updates push command to use the provider abstraction: - Initializes provider registry with setup.Init() - Detects target registry via provider.ForImage() - Uses isReplicate flag for provider-specific behavior - Local image push (--local-image) now explicitly Replicate-only with clear error - 404 errors now show registry-appropriate messages - Replicate model URL only shown when pushing to Replicate This makes the push command work with any OCI registry while maintaining Replicate-specific features and helpful error messages. * refactor(cli): use generic examples in push/pull commands Updates command examples and error messages to use generic registry placeholders instead of hardcoded r8.im references: - 'cog push registry.example.com/your-username/model-name' - 'cog pull registry.example.com/your-username/model-name' This makes the documentation more neutral while still being clear about how to use the commands with any OCI registry. * feat(cli): warn and disable fast push for non-Replicate registries When --x-fast flag is used with a non-Replicate registry, instead of failing or silently ignoring: - Shows a warning that fast push is Replicate-only - Automatically falls back to standard push This maintains backward compatibility while clearly communicating the feature limitation to users. * refactor(cli): make coglog analytics conditional for Replicate Analytics (coglog) calls are now only made when pushing to Replicate: - Moved config/image detection before Docker client creation - Determine isReplicate flag before initializing analytics - logClient.StartPush() and EndPush() only called for Replicate - Simplified error handling with endPushWithError helper This ensures non-Replicate push operations don't attempt to contact Replicate's analytics endpoints, improving privacy and performance when using other registries. * docs: update CLI documentation for multi-registry support - Add documentation for pushing to non-Replicate registries (GHCR, GCR, etc.) - Clarify that 'cog login' is for Replicate; use 'docker login' for others - Add examples showing multi-registry workflows * refactor: use PrePush/PostPush hooks instead of isReplicate checks Major refactoring to move registry-specific logic into provider hooks: Provider interface changes: - Add PushOptions struct to consolidate all push parameters - PrePush(ctx, opts) validates options and starts analytics - PostPush(ctx, opts, pushErr) ends analytics and shows messages GenericProvider: - PrePush() errors on --local-image (not supported) - PrePush() warns on --x-fast (not supported, falls back) - PostPush() shows simple success message ReplicateProvider: - PrePush() starts coglog analytics, shows 'Fast push enabled' - PostPush() ends analytics, shows Replicate URL on success - PostPush() returns Replicate-specific error messages for 404s push.go is now much cleaner: - No more scattered isReplicate checks (reduced from 6+ to 1) - Single PrePush/PostPush call handles all provider-specific behavior - Generic flow: setup -> PrePush -> build -> push -> PostPush The remaining p.Name() check is for disabling FastPush after warning, which could be improved with a SupportsFastPush() method in the future. * feat(provider): implement interactive login for generic registries GenericProvider now handles login directly by prompting for username and password, then saving credentials via Docker's credential system. Changes: - GenericProvider.Login() prompts interactively instead of returning ErrUseDockerLogin - Remove ErrUseDockerLogin since it's no longer needed - Update login.go to remove ErrUseDockerLogin handling - Update help text to reflect that 'cog login' works for all registries * docs: document --registry flag for multi-registry login support - Add --registry to Global Options in cli.md and llms.txt - Update cog login examples to show --registry usage for non-Replicate registries - Clarify that --token-stdin is Replicate-specific * refactor: use typed errors for push repository not found Replace string-based '404' error checking with typed NotFoundError: - Add isRepositoryNotFoundError() to detect NAME_UNKNOWN registry errors - Convert NAME_UNKNOWN to NotFoundError{Object: "repository"} in Push() - Update ReplicateProvider.PostPush() to use command.IsNotFoundError() - Remove string wrapper from StandardPush() since error is now typed - Add tests for NotFoundError handling in PostPush * chore: cleanup Signed-off-by: Mark Phelps <mphelps@cloudflare.com> * chore: debug Signed-off-by: Mark Phelps <mphelps@cloudflare.com> * chore: fix build Signed-off-by: Mark Phelps <mphelps@cloudflare.com> * chore: fix lint error Signed-off-by: Mark Phelps <mphelps@cloudflare.com> * chore: fix generic login/host Signed-off-by: Mark Phelps <mphelps@cloudflare.com> * chore: fix build Signed-off-by: Mark Phelps <mphelps@cloudflare.com> * test: add integration tests for login command Add comprehensive integration tests for the login command changes: - TestLoginGenericRegistryPTY: Tests interactive login flow for generic registries with PTY-based username/password prompts - TestLoginProviderRouting: Verifies correct provider selection based on --registry flag (Replicate for r8.im, generic for others) - TestLoginEnvironmentVariable: Tests COG_REGISTRY_HOST env var and --registry flag override behavior - TestLoginHelp: Verifies help text mentions both Replicate and generic registry support - TestLoginSuggestFor: Verifies 'cog auth' suggests 'cog login' The tests use PTY interaction for generic provider login since it requires interactive username/password input. Replicate-specific token verification is tested in unit tests (pkg/provider/replicate/). * refactor: use raw string literal for multi-line error message --------- Signed-off-by: Mark Phelps <mphelps@cloudflare.com> Signed-off-by: Mark Phelps <209477+markphelps@users.noreply.github.com>
Author
Parents
Loading