diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-29 10:52:50 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-29 10:52:50 +0300 |
| commit | 714e81e56b3e8d49359c8098ec85dbaac8f74d4c (patch) | |
| tree | 9e91ca8cf643449a5a7edca3a4606afe024c6e26 | |
| parent | 4513ccec70871532b5b06aed3f9ed720abf613ed (diff) | |
refactor(cli): inject repo client factory for mq
| -rw-r--r-- | internal/cli/description_sync.go | 23 | ||||
| -rw-r--r-- | internal/cli/repo_client_factory.go | 54 | ||||
| -rw-r--r-- | internal/cli/repo_client_factory_injection_test.go | 243 | ||||
| -rw-r--r-- | internal/cli/sync_handlers.go | 59 | ||||
| -rw-r--r-- | internal/codeberg/codeberg.go | 11 | ||||
| -rw-r--r-- | internal/forge/repo_ops.go | 7 | ||||
| -rw-r--r-- | internal/github/github.go | 10 |
7 files changed, 372 insertions, 35 deletions
diff --git a/internal/cli/description_sync.go b/internal/cli/description_sync.go index 6a83c1e..cb008ca 100644 --- a/internal/cli/description_sync.go +++ b/internal/cli/description_sync.go @@ -8,26 +8,29 @@ import ( "path/filepath" "strings" - "codeberg.org/snonux/gitsyncer/internal/codeberg" "codeberg.org/snonux/gitsyncer/internal/config" - "codeberg.org/snonux/gitsyncer/internal/github" + "codeberg.org/snonux/gitsyncer/internal/forge" ) // syncRepoDescriptions ensures both platforms have the canonical description // Precedence: Codeberg > GitHub; if Codeberg empty and GitHub has one, use GitHub. // knownCBDesc and knownGHDesc can be empty; the function fetches as needed. func syncRepoDescriptions(cfg *config.Config, dryRun bool, repoName, knownCBDesc, knownGHDesc string, cache map[string]string) { + syncRepoDescriptionsWithFactory(cfg, dryRun, repoName, knownCBDesc, knownGHDesc, cache, cliRepoClientFactory) +} + +func syncRepoDescriptionsWithFactory(cfg *config.Config, dryRun bool, repoName, knownCBDesc, knownGHDesc string, cache map[string]string, factory repoClientFactory) { // Load orgs ghOrg := cfg.FindGitHubOrg() cbOrg := cfg.FindCodebergOrg() - var ghClient *github.Client - var cbClient *codeberg.Client + var ghClient forge.RepoDescriptionClient + var cbClient forge.RepoDescriptionClient if ghOrg != nil { - ghClient = github.NewClient(ghOrg.GitHubToken, ghOrg.Name) + ghClient = factory.NewGitHubDescriptionClient(ghOrg.GitHubToken, ghOrg.Name) } if cbOrg != nil { - cbClient = codeberg.NewClient(cbOrg.CodebergToken, cbOrg.Name) + cbClient = factory.NewCodebergDescriptionClient(cbOrg.CodebergToken, cbOrg.Name) } // Get current descriptions (use known if provided) @@ -36,10 +39,10 @@ func syncRepoDescriptions(cfg *config.Config, dryRun bool, repoName, knownCBDesc var cbExists, ghExists bool if cbDesc == "" && cbClient != nil { - if repo, exists, err := cbClient.GetRepo(repoName); err == nil { + if description, exists, err := cbClient.GetRepoDescription(repoName); err == nil { cbExists = exists if exists { - cbDesc = strings.TrimSpace(repo.Description) + cbDesc = strings.TrimSpace(description) } } else { fmt.Printf(" Warning: Codeberg repo lookup failed: %v\n", err) @@ -50,10 +53,10 @@ func syncRepoDescriptions(cfg *config.Config, dryRun bool, repoName, knownCBDesc if ghClient != nil { if ghDesc == "" || !ghExists { - if repo, exists, err := ghClient.GetRepo(repoName); err == nil { + if description, exists, err := ghClient.GetRepoDescription(repoName); err == nil { ghExists = exists if exists { - ghDesc = strings.TrimSpace(repo.Description) + ghDesc = strings.TrimSpace(description) } } else { fmt.Printf(" Warning: GitHub repo lookup failed: %v\n", err) diff --git a/internal/cli/repo_client_factory.go b/internal/cli/repo_client_factory.go new file mode 100644 index 0000000..242a1c0 --- /dev/null +++ b/internal/cli/repo_client_factory.go @@ -0,0 +1,54 @@ +package cli + +import ( + "codeberg.org/snonux/gitsyncer/internal/codeberg" + "codeberg.org/snonux/gitsyncer/internal/forge" + "codeberg.org/snonux/gitsyncer/internal/github" +) + +type githubPublicRepoClient interface { + HasToken() bool + ListPublicRepos() ([]github.Repository, error) +} + +type codebergPublicRepoClient interface { + ListPublicRepos() ([]codeberg.Repository, error) + ListUserPublicRepos() ([]codeberg.Repository, error) +} + +type repoClientFactory interface { + NewGitHubRepoClient(token, org string) forge.RepoClient + NewCodebergRepoClient(token, org string) forge.RepoClient + NewGitHubDescriptionClient(token, org string) forge.RepoDescriptionClient + NewCodebergDescriptionClient(token, org string) forge.RepoDescriptionClient + NewGitHubPublicRepoClient(token, org string) githubPublicRepoClient + NewCodebergPublicRepoClient(token, org string) codebergPublicRepoClient +} + +type defaultRepoClientFactory struct{} + +func (defaultRepoClientFactory) NewGitHubRepoClient(token, org string) forge.RepoClient { + return github.NewClient(token, org) +} + +func (defaultRepoClientFactory) NewCodebergRepoClient(token, org string) forge.RepoClient { + return codeberg.NewClient(token, org) +} + +func (defaultRepoClientFactory) NewGitHubDescriptionClient(token, org string) forge.RepoDescriptionClient { + return github.NewClient(token, org) +} + +func (defaultRepoClientFactory) NewCodebergDescriptionClient(token, org string) forge.RepoDescriptionClient { + return codeberg.NewClient(token, org) +} + +func (defaultRepoClientFactory) NewGitHubPublicRepoClient(token, org string) githubPublicRepoClient { + return github.NewClient(token, org) +} + +func (defaultRepoClientFactory) NewCodebergPublicRepoClient(token, org string) codebergPublicRepoClient { + return codeberg.NewClient(token, org) +} + +var cliRepoClientFactory repoClientFactory = defaultRepoClientFactory{} diff --git a/internal/cli/repo_client_factory_injection_test.go b/internal/cli/repo_client_factory_injection_test.go new file mode 100644 index 0000000..5a572ae --- /dev/null +++ b/internal/cli/repo_client_factory_injection_test.go @@ -0,0 +1,243 @@ +package cli + +import ( + "testing" + + "codeberg.org/snonux/gitsyncer/internal/codeberg" + "codeberg.org/snonux/gitsyncer/internal/config" + "codeberg.org/snonux/gitsyncer/internal/forge" + "codeberg.org/snonux/gitsyncer/internal/github" +) + +type createCall struct { + repoName string + description string + privateRepo bool +} + +type updateCall struct { + repoName string + description string +} + +type stubDescriptionRepoClient struct { + hasToken bool + descriptionByRepo map[string]string + updatedDescription []updateCall + createCalls []createCall +} + +func (s *stubDescriptionRepoClient) HasToken() bool { return s.hasToken } + +func (s *stubDescriptionRepoClient) RepoExists(repoName string) (bool, error) { + _, exists := s.descriptionByRepo[repoName] + return exists, nil +} + +func (s *stubDescriptionRepoClient) CreateRepo(repoName, description string, private bool) error { + s.createCalls = append(s.createCalls, createCall{ + repoName: repoName, + description: description, + privateRepo: private, + }) + return nil +} + +func (s *stubDescriptionRepoClient) DeleteRepo(_ string) error { + return nil +} + +func (s *stubDescriptionRepoClient) GetRepoDescription(repoName string) (string, bool, error) { + description, exists := s.descriptionByRepo[repoName] + return description, exists, nil +} + +func (s *stubDescriptionRepoClient) UpdateRepoDescription(repoName, description string) error { + s.updatedDescription = append(s.updatedDescription, updateCall{ + repoName: repoName, + description: description, + }) + if s.descriptionByRepo == nil { + s.descriptionByRepo = map[string]string{} + } + s.descriptionByRepo[repoName] = description + return nil +} + +type stubGitHubPublicRepoClient struct { + hasToken bool + repos []github.Repository +} + +func (s *stubGitHubPublicRepoClient) HasToken() bool { + return s.hasToken +} + +func (s *stubGitHubPublicRepoClient) ListPublicRepos() ([]github.Repository, error) { + return s.repos, nil +} + +type stubCodebergPublicRepoClient struct { + orgRepos []codeberg.Repository + userRepos []codeberg.Repository +} + +func (s *stubCodebergPublicRepoClient) ListPublicRepos() ([]codeberg.Repository, error) { + return s.orgRepos, nil +} + +func (s *stubCodebergPublicRepoClient) ListUserPublicRepos() ([]codeberg.Repository, error) { + return s.userRepos, nil +} + +type stubRepoClientFactory struct { + githubRepoClient forge.RepoClient + codebergRepoClient forge.RepoClient + githubDescriptionClient forge.RepoDescriptionClient + codebergDescClient forge.RepoDescriptionClient + githubPublicClient githubPublicRepoClient + codebergPublicClient codebergPublicRepoClient + + githubRepoCalls int + codebergRepoCalls int + githubDescCalls int + codebergDescCalls int + githubPublicRepoCalls int + codebergPublicCalls int +} + +func (s *stubRepoClientFactory) NewGitHubRepoClient(_, _ string) forge.RepoClient { + s.githubRepoCalls++ + return s.githubRepoClient +} + +func (s *stubRepoClientFactory) NewCodebergRepoClient(_, _ string) forge.RepoClient { + s.codebergRepoCalls++ + return s.codebergRepoClient +} + +func (s *stubRepoClientFactory) NewGitHubDescriptionClient(_, _ string) forge.RepoDescriptionClient { + s.githubDescCalls++ + return s.githubDescriptionClient +} + +func (s *stubRepoClientFactory) NewCodebergDescriptionClient(_, _ string) forge.RepoDescriptionClient { + s.codebergDescCalls++ + return s.codebergDescClient +} + +func (s *stubRepoClientFactory) NewGitHubPublicRepoClient(_, _ string) githubPublicRepoClient { + s.githubPublicRepoCalls++ + return s.githubPublicClient +} + +func (s *stubRepoClientFactory) NewCodebergPublicRepoClient(_, _ string) codebergPublicRepoClient { + s.codebergPublicCalls++ + return s.codebergPublicClient +} + +func TestSyncRepoDescriptionsWithFactory_UsesInjectedClients(t *testing.T) { + t.Parallel() + + githubClient := &stubDescriptionRepoClient{ + hasToken: true, + descriptionByRepo: map[string]string{"demo": "from github"}, + } + codebergClient := &stubDescriptionRepoClient{ + hasToken: true, + descriptionByRepo: map[string]string{"demo": "from codeberg"}, + } + factory := &stubRepoClientFactory{ + githubDescriptionClient: githubClient, + codebergDescClient: codebergClient, + } + + cfg := &config.Config{ + Organizations: []config.Organization{ + { + Host: "git@github.com", + Name: "acme", + GitHubToken: "gh-token", + CodebergToken: "", + }, + { + Host: "git@codeberg.org", + Name: "acme", + CodebergToken: "cb-token", + }, + }, + } + cache := map[string]string{} + + syncRepoDescriptionsWithFactory(cfg, false, "demo", "", "", cache, factory) + + if factory.githubDescCalls != 1 || factory.codebergDescCalls != 1 { + t.Fatalf("expected one injected description client creation per forge, got github=%d codeberg=%d", factory.githubDescCalls, factory.codebergDescCalls) + } + + if len(codebergClient.updatedDescription) != 0 { + t.Fatalf("expected no Codeberg update when it already has canonical description, got %d updates", len(codebergClient.updatedDescription)) + } + + if len(githubClient.updatedDescription) != 1 { + t.Fatalf("expected GitHub description to be updated once, got %d updates", len(githubClient.updatedDescription)) + } + if githubClient.updatedDescription[0].description != "from codeberg" { + t.Fatalf("github description update = %q, want %q", githubClient.updatedDescription[0].description, "from codeberg") + } + + if cache["demo"] != "from codeberg" { + t.Fatalf("cache description = %q, want %q", cache["demo"], "from codeberg") + } +} + +func TestCreateRepoHelpersWithFactory_UseInjectedCreateClients(t *testing.T) { + t.Parallel() + + githubClient := &stubDescriptionRepoClient{hasToken: true} + codebergClient := &stubDescriptionRepoClient{hasToken: true} + factory := &stubRepoClientFactory{ + githubRepoClient: githubClient, + codebergRepoClient: codebergClient, + } + + cfg := &config.Config{ + Organizations: []config.Organization{ + { + Host: "git@github.com", + Name: "acme", + GitHubToken: "gh-token", + }, + { + Host: "git@codeberg.org", + Name: "acme", + CodebergToken: "cb-token", + }, + }, + } + + if err := createGitHubRepoIfNeededWithFactory(cfg, "demo", factory); err != nil { + t.Fatalf("createGitHubRepoIfNeededWithFactory() error = %v", err) + } + if err := createCodebergRepoIfNeededWithFactory(cfg, "demo", factory); err != nil { + t.Fatalf("createCodebergRepoIfNeededWithFactory() error = %v", err) + } + + if factory.githubRepoCalls != 1 || factory.codebergRepoCalls != 1 { + t.Fatalf("expected one injected create client per forge, got github=%d codeberg=%d", factory.githubRepoCalls, factory.codebergRepoCalls) + } + + if len(githubClient.createCalls) != 1 { + t.Fatalf("expected one GitHub create call, got %d", len(githubClient.createCalls)) + } + if len(codebergClient.createCalls) != 1 { + t.Fatalf("expected one Codeberg create call, got %d", len(codebergClient.createCalls)) + } + + if githubClient.createCalls[0].description != "Mirror of demo" { + t.Fatalf("github create description = %q, want %q", githubClient.createCalls[0].description, "Mirror of demo") + } + if codebergClient.createCalls[0].description != "Mirror of demo" { + t.Fatalf("codeberg create description = %q, want %q", codebergClient.createCalls[0].description, "Mirror of demo") + } +} diff --git a/internal/cli/sync_handlers.go b/internal/cli/sync_handlers.go index e0c62de..df0b6b0 100644 --- a/internal/cli/sync_handlers.go +++ b/internal/cli/sync_handlers.go @@ -7,6 +7,7 @@ import ( "codeberg.org/snonux/gitsyncer/internal/codeberg" "codeberg.org/snonux/gitsyncer/internal/config" + "codeberg.org/snonux/gitsyncer/internal/forge" "codeberg.org/snonux/gitsyncer/internal/github" "codeberg.org/snonux/gitsyncer/internal/state" "codeberg.org/snonux/gitsyncer/internal/sync" @@ -95,13 +96,13 @@ func HandleSyncAll(cfg *config.Config, flags *Flags) int { } // Initialize GitHub client if needed - var githubClient *github.Client + var githubClient forge.RepoClient if flags.CreateGitHubRepos { githubClient = initGitHubClient(cfg) } // Initialize Codeberg client if needed - var codebergClient *codeberg.Client + var codebergClient forge.RepoClient if flags.CreateCodebergRepos { codebergClient = initCodebergClient(cfg) } @@ -188,7 +189,7 @@ func HandleSyncCodebergPublic(cfg *config.Config, flags *Flags) int { fmt.Printf("Fetching public repositories from Codeberg user/org: %s...\n", codebergOrg.Name) - client := codeberg.NewClient(codebergOrg.CodebergToken, codebergOrg.Name) + client := cliRepoClientFactory.NewCodebergPublicRepoClient(codebergOrg.CodebergToken, codebergOrg.Name) // Try fetching as organization first, then as user repos, err := client.ListPublicRepos() @@ -245,7 +246,7 @@ func HandleSyncGitHubPublic(cfg *config.Config, flags *Flags) int { fmt.Printf("Fetching public repositories from GitHub user/org: %s...\n", githubOrg.Name) - client := github.NewClient(githubOrg.GitHubToken, githubOrg.Name) + client := cliRepoClientFactory.NewGitHubPublicRepoClient(githubOrg.GitHubToken, githubOrg.Name) if !client.HasToken() { fmt.Println("ERROR: GitHub token required to list repositories") fmt.Println("Set GITHUB_TOKEN env var or create ~/.gitsyncer_github_token file") @@ -293,13 +294,17 @@ func HandleSyncGitHubPublic(cfg *config.Config, flags *Flags) int { // Helper functions func createGitHubRepoIfNeeded(cfg *config.Config, repoName string) error { + return createGitHubRepoIfNeededWithFactory(cfg, repoName, cliRepoClientFactory) +} + +func createGitHubRepoIfNeededWithFactory(cfg *config.Config, repoName string, factory repoClientFactory) error { githubOrg := cfg.FindGitHubOrg() if githubOrg == nil { return nil } fmt.Printf("Initializing GitHub client for organization: %s\n", githubOrg.Name) - githubClient := github.NewClient(githubOrg.GitHubToken, githubOrg.Name) + githubClient := factory.NewGitHubRepoClient(githubOrg.GitHubToken, githubOrg.Name) if !githubClient.HasToken() { fmt.Println("Warning: No GitHub token found. Cannot create repository.") return nil @@ -310,13 +315,17 @@ func createGitHubRepoIfNeeded(cfg *config.Config, repoName string) error { } func createCodebergRepoIfNeeded(cfg *config.Config, repoName string) error { + return createCodebergRepoIfNeededWithFactory(cfg, repoName, cliRepoClientFactory) +} + +func createCodebergRepoIfNeededWithFactory(cfg *config.Config, repoName string, factory repoClientFactory) error { codebergOrg := cfg.FindCodebergOrg() if codebergOrg == nil { return nil } fmt.Printf("Initializing Codeberg client for organization: %s\n", codebergOrg.Name) - codebergClient := codeberg.NewClient(codebergOrg.CodebergToken, codebergOrg.Name) + codebergClient := factory.NewCodebergRepoClient(codebergOrg.CodebergToken, codebergOrg.Name) if !codebergClient.HasToken() { fmt.Println("Warning: No Codeberg token found. Cannot create repository.") return nil @@ -326,7 +335,11 @@ func createCodebergRepoIfNeeded(cfg *config.Config, repoName string) error { return codebergClient.CreateRepo(repoName, fmt.Sprintf("Mirror of %s", repoName), false) } -func initGitHubClient(cfg *config.Config) *github.Client { +func initGitHubClient(cfg *config.Config) forge.RepoClient { + return initGitHubClientWithFactory(cfg, cliRepoClientFactory) +} + +func initGitHubClientWithFactory(cfg *config.Config, factory repoClientFactory) forge.RepoClient { githubOrg := cfg.FindGitHubOrg() if githubOrg == nil { fmt.Println("Warning: --create-github-repos specified but no GitHub organization found in config") @@ -334,7 +347,7 @@ func initGitHubClient(cfg *config.Config) *github.Client { } fmt.Printf("Initializing GitHub client for organization: %s\n", githubOrg.Name) - githubClient := github.NewClient(githubOrg.GitHubToken, githubOrg.Name) + githubClient := factory.NewGitHubRepoClient(githubOrg.GitHubToken, githubOrg.Name) if !githubClient.HasToken() { fmt.Println("Warning: No GitHub token found. Cannot create repositories.") return nil @@ -344,12 +357,16 @@ func initGitHubClient(cfg *config.Config) *github.Client { return githubClient } -func createRepoWithClient(client *github.Client, repoName, description string) error { +func createRepoWithClient(client forge.RepoClient, repoName, description string) error { fmt.Printf("Checking/creating GitHub repository %s...\n", repoName) return client.CreateRepo(repoName, description, false) } -func initCodebergClient(cfg *config.Config) *codeberg.Client { +func initCodebergClient(cfg *config.Config) forge.RepoClient { + return initCodebergClientWithFactory(cfg, cliRepoClientFactory) +} + +func initCodebergClientWithFactory(cfg *config.Config, factory repoClientFactory) forge.RepoClient { codebergOrg := cfg.FindCodebergOrg() if codebergOrg == nil { fmt.Println("Warning: --create-codeberg-repos specified but no Codeberg organization found in config") @@ -357,7 +374,7 @@ func initCodebergClient(cfg *config.Config) *codeberg.Client { } fmt.Printf("Initializing Codeberg client for organization: %s\n", codebergOrg.Name) - codebergClient := codeberg.NewClient(codebergOrg.CodebergToken, codebergOrg.Name) + codebergClient := factory.NewCodebergRepoClient(codebergOrg.CodebergToken, codebergOrg.Name) if !codebergClient.HasToken() { fmt.Println("Warning: No Codeberg token found. Cannot create repositories.") return nil @@ -504,13 +521,9 @@ func printDeleteScript(syncer *sync.Syncer) { func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Repository, repoNames []string) int { // Initialize GitHub client if needed - var githubClient github.Client - var hasGithubClient bool + var githubClient forge.RepoClient if flags.CreateGitHubRepos { - if client := initGitHubClient(cfg); client != nil { - githubClient = *client - hasGithubClient = true - } + githubClient = initGitHubClient(cfg) } fmt.Printf("\nStarting sync of %d repositories...\n", len(repoNames)) @@ -532,7 +545,7 @@ func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Reposi } // Create GitHub repo if needed - if hasGithubClient && flags.CreateGitHubRepos { + if githubClient != nil && flags.CreateGitHubRepos { codebergRepo := repoMap[repoName] description := codebergRepo.Description if description == "" { @@ -575,13 +588,9 @@ func syncCodebergRepos(cfg *config.Config, flags *Flags, repos []codeberg.Reposi func syncGitHubRepos(cfg *config.Config, flags *Flags, repos []github.Repository, repoNames []string) int { // Initialize Codeberg client if needed - var codebergClient codeberg.Client - var hasCodebergClient bool + var codebergClient forge.RepoClient if flags.CreateCodebergRepos { - if client := initCodebergClient(cfg); client != nil { - codebergClient = *client - hasCodebergClient = true - } + codebergClient = initCodebergClient(cfg) } fmt.Printf("\nStarting sync of %d repositories...\n", len(repoNames)) @@ -603,7 +612,7 @@ func syncGitHubRepos(cfg *config.Config, flags *Flags, repos []github.Repository } // Create Codeberg repo if needed - if hasCodebergClient && flags.CreateCodebergRepos { + if codebergClient != nil && flags.CreateCodebergRepos { githubRepo := repoMap[repoName] description := githubRepo.Description if description == "" { diff --git a/internal/codeberg/codeberg.go b/internal/codeberg/codeberg.go index 0d587de..f881be9 100644 --- a/internal/codeberg/codeberg.go +++ b/internal/codeberg/codeberg.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "time" "codeberg.org/snonux/gitsyncer/internal/forge" @@ -39,6 +40,7 @@ type Client struct { } var _ forge.RepoClient = (*Client)(nil) +var _ forge.RepoDescriptionClient = (*Client)(nil) // NewClient creates a new Codeberg API client func NewClient(token, org string) *Client { @@ -111,6 +113,15 @@ func (c *Client) GetRepo(repoName string) (Repository, bool, error) { return repo, true, nil } +// GetRepoDescription fetches a repository description. +func (c *Client) GetRepoDescription(repoName string) (string, bool, error) { + repo, exists, err := c.GetRepo(repoName) + if err != nil || !exists { + return "", exists, err + } + return strings.TrimSpace(repo.Description), true, nil +} + // UpdateRepoDescription updates a repository description on Codeberg func (c *Client) UpdateRepoDescription(repoName, description string) error { if !c.HasToken() { diff --git a/internal/forge/repo_ops.go b/internal/forge/repo_ops.go index 8334a16..6459ec6 100644 --- a/internal/forge/repo_ops.go +++ b/internal/forge/repo_ops.go @@ -10,6 +10,13 @@ type RepoClient interface { DeleteRepo(repoName string) error } +// RepoDescriptionClient defines shared description operations across forges. +type RepoDescriptionClient interface { + RepoClient + GetRepoDescription(repoName string) (string, bool, error) + UpdateRepoDescription(repoName, description string) error +} + // RepoExistsFunc checks if a repository exists. type RepoExistsFunc func(repoName string) (bool, error) diff --git a/internal/github/github.go b/internal/github/github.go index e48fc50..66e0f67 100644 --- a/internal/github/github.go +++ b/internal/github/github.go @@ -21,6 +21,7 @@ type Client struct { } var _ forge.RepoClient = (*Client)(nil) +var _ forge.RepoDescriptionClient = (*Client)(nil) // NewClient creates a new GitHub API client func NewClient(token, org string) *Client { @@ -231,6 +232,15 @@ func (c *Client) GetRepo(repoName string) (Repository, bool, error) { return repo, true, nil } +// GetRepoDescription fetches a repository description. +func (c *Client) GetRepoDescription(repoName string) (string, bool, error) { + repo, exists, err := c.GetRepo(repoName) + if err != nil || !exists { + return "", exists, err + } + return strings.TrimSpace(repo.Description), true, nil +} + // UpdateRepoDescription updates the repository description func (c *Client) UpdateRepoDescription(repoName, description string) error { if c.token == "" { |
