package cmd import ( "fmt" "os" "os/exec" "path/filepath" "text/tabwriter" "code.gitea.io/sdk/gitea" "github.com/spf13/cobra" "codeberg.org/romaintb/fgj/internal/api" "codeberg.org/romaintb/fgj/internal/config" ) var repoCmd = &cobra.Command{ Use: "repo", Short: "Manage repositories", Long: "View and manage repositories.", } var repoViewCmd = &cobra.Command{ Use: "view [owner/name]", Short: "View repository details", Long: "Display detailed information about a repository.", Args: cobra.MaximumNArgs(1), RunE: runRepoView, } var repoListCmd = &cobra.Command{ Use: "list", Short: "List your repositories", Long: "List repositories owned by the authenticated user.", RunE: runRepoList, } var repoCloneCmd = &cobra.Command{ Use: "clone [destination]", Short: "Clone a repository", Long: "Clone a repository locally. If destination is not specified, the repository name is used.", Args: cobra.RangeArgs(1, 2), RunE: runRepoClone, } var repoForkCmd = &cobra.Command{ Use: "fork ", Short: "Fork a repository", Long: "Create a fork of a repository.", Args: cobra.ExactArgs(1), RunE: runRepoFork, } func init() { rootCmd.AddCommand(repoCmd) repoCmd.AddCommand(repoViewCmd) repoCmd.AddCommand(repoListCmd) repoCmd.AddCommand(repoCloneCmd) repoCmd.AddCommand(repoForkCmd) repoCloneCmd.Flags().StringP("protocol", "p", "https", "Clone protocol: https or ssh") } func runRepoView(cmd *cobra.Command, args []string) error { var repo string if len(args) > 0 { repo = args[0] } owner, name, err := parseRepo(repo) if err != nil { return err } cfg, err := config.Load() if err != nil { return err } client, err := api.NewClientFromConfig(cfg, "") if err != nil { return err } repository, _, err := client.GetRepo(owner, name) if err != nil { return fmt.Errorf("failed to get repository: %w", err) } fmt.Printf("Repository: %s/%s\n", repository.Owner.UserName, repository.Name) fmt.Printf("Description: %s\n", repository.Description) fmt.Printf("URL: %s\n", repository.HTMLURL) fmt.Printf("Clone URL (HTTPS): %s\n", repository.CloneURL) fmt.Printf("Clone URL (SSH): %s\n", repository.SSHURL) fmt.Printf("Default Branch: %s\n", repository.DefaultBranch) fmt.Printf("Stars: %d\n", repository.Stars) fmt.Printf("Forks: %d\n", repository.Forks) fmt.Printf("Open Issues: %d\n", repository.OpenIssues) fmt.Printf("Private: %v\n", repository.Private) fmt.Printf("Created: %s\n", repository.Created.Format("2006-01-02 15:04:05")) fmt.Printf("Updated: %s\n", repository.Updated.Format("2006-01-02 15:04:05")) return nil } func runRepoList(cmd *cobra.Command, args []string) error { cfg, err := config.Load() if err != nil { return err } client, err := api.NewClientFromConfig(cfg, "") if err != nil { return err } user, _, err := client.GetMyUserInfo() if err != nil { return fmt.Errorf("failed to get user info: %w", err) } repos, _, err := client.ListUserRepos(user.UserName, gitea.ListReposOptions{}) if err != nil { return fmt.Errorf("failed to list repositories: %w", err) } if len(repos) == 0 { fmt.Println("No repositories found") return nil } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) _, _ = fmt.Fprintf(w, "NAME\tVISIBILITY\tDESCRIPTION\n") for _, repo := range repos { visibility := "public" if repo.Private { visibility = "private" } desc := repo.Description if len(desc) > 50 { desc = desc[:47] + "..." } _, _ = fmt.Fprintf(w, "%s/%s\t%s\t%s\n", repo.Owner.UserName, repo.Name, visibility, desc) } _ = w.Flush() return nil } func runRepoClone(cmd *cobra.Command, args []string) error { repo := args[0] protocol, _ := cmd.Flags().GetString("protocol") owner, name, err := parseRepo(repo) if err != nil { return err } cfg, err := config.Load() if err != nil { return err } client, err := api.NewClientFromConfig(cfg, "") if err != nil { return err } repository, _, err := client.GetRepo(owner, name) if err != nil { return fmt.Errorf("failed to get repository: %w", err) } var cloneURL string if protocol == "ssh" { cloneURL = repository.SSHURL } else { cloneURL = repository.CloneURL } // Determine destination path var destination string if len(args) > 1 { destination = args[1] } else { destination = name } fmt.Printf("Cloning %s/%s to %s...\n", owner, name, destination) // Create parent directory if it doesn't exist if dir := filepath.Dir(destination); dir != "." { if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("failed to create destination directory: %w", err) } } // Execute git clone gitCmd := exec.Command("git", "clone", cloneURL, destination) gitCmd.Stdout = os.Stdout gitCmd.Stderr = os.Stderr gitCmd.Stdin = os.Stdin if err := gitCmd.Run(); err != nil { return fmt.Errorf("failed to clone repository: %w", err) } fmt.Printf("Repository cloned successfully to %s\n", destination) return nil } func runRepoFork(cmd *cobra.Command, args []string) error { repo := args[0] owner, name, err := parseRepo(repo) if err != nil { return err } cfg, err := config.Load() if err != nil { return err } client, err := api.NewClientFromConfig(cfg, "") if err != nil { return err } fork, _, err := client.CreateFork(owner, name, gitea.CreateForkOption{}) if err != nil { return fmt.Errorf("failed to fork repository: %w", err) } fmt.Printf("Repository forked successfully\n") fmt.Printf("View at: %s\n", fork.HTMLURL) fmt.Printf("Clone URL: %s\n", fork.CloneURL) return nil }