diff --git a/cmd/repos.go b/cmd/repos.go index e2ba07f..75e0644 100644 --- a/cmd/repos.go +++ b/cmd/repos.go @@ -5,26 +5,32 @@ package cmd import ( + "fmt" "log" + "net/http" + "strings" + + "code.gitea.io/tea/modules/utils" "code.gitea.io/sdk/gitea" - "github.com/urfave/cli/v2" ) // CmdRepos represents to login a gitea server. var CmdRepos = cli.Command{ Name: "repos", - Usage: "Operate with repositories", - Description: `Operate with repositories`, - Action: runReposList, + Usage: "Show repositories details", + Description: "Show repositories details", + ArgsUsage: "[/]", + Action: runRepos, Subcommands: []*cli.Command{ &CmdReposList, + &CmdRepoCreate, }, Flags: LoginOutputFlags, } -// CmdReposList represents a sub command of issues to list issues +// CmdReposList represents a sub command of repos to list them var CmdReposList = cli.Command{ Name: "ls", Usage: "List available repositories", @@ -32,66 +38,164 @@ var CmdReposList = cli.Command{ Action: runReposList, Flags: append([]cli.Flag{ &cli.StringFlag{ - Name: "mode", - Usage: "Filter listed repositories based on mode, optional - fork, mirror, source", + Name: "mode", + Aliases: []string{"m"}, + Required: false, + Usage: "Filter by mode: fork, mirror, source", }, &cli.StringFlag{ - Name: "org", - Usage: "Filter listed repositories based on organization, optional", + Name: "owner", + Aliases: []string{"O"}, + Required: false, + Usage: "Filter by owner", }, &cli.StringFlag{ - Name: "user", - Usage: "Filter listed repositories absed on user, optional", + Name: "private", + Required: false, + Usage: "Filter private repos (true|false)", + }, + &cli.StringFlag{ + Name: "archived", + Required: false, + Usage: "Filter archived repos (true|false)", }, }, LoginOutputFlags...), } +// CmdRepoCreate represents a sub command of repos to create one +var CmdRepoCreate = cli.Command{ + Name: "create", + Aliases: []string{"c"}, + Usage: "Create a repository", + Description: "Create a repository", + Action: runRepoCreate, + Flags: append([]cli.Flag{ + &cli.StringFlag{ + Name: "name", + Aliases: []string{""}, + Required: true, + Usage: "name of new repo", + }, + &cli.StringFlag{ + Name: "owner", + Aliases: []string{"O"}, + Required: false, + Usage: "name of repo owner", + }, + &cli.BoolFlag{ + Name: "private", + Required: false, + Value: false, + Usage: "make repo private", + }, + &cli.StringFlag{ + Name: "description", + Aliases: []string{"desc"}, + Required: false, + Usage: "add description to repo", + }, + &cli.BoolFlag{ + Name: "init", + Required: false, + Value: false, + Usage: "initialize repo", + }, + &cli.StringFlag{ + Name: "labels", + Required: false, + Usage: "name of label set to add", + }, + &cli.StringFlag{ + Name: "gitignores", + Aliases: []string{"git"}, + Required: false, + Usage: "list of gitignore templates (need --init)", + }, + &cli.StringFlag{ + Name: "license", + Required: false, + Usage: "add license (need --init)", + }, + &cli.StringFlag{ + Name: "readme", + Required: false, + Usage: "use readme template (need --init)", + }, + &cli.StringFlag{ + Name: "branch", + Required: false, + Usage: "use custom default branch (need --init)", + }, + }, LoginOutputFlags...), +} + +func runRepos(ctx *cli.Context) error { + if ctx.Args().Len() == 1 { + return runRepoDetail(ctx, ctx.Args().First()) + } + return runReposList(ctx) +} + // runReposList list repositories func runReposList(ctx *cli.Context) error { login := initCommandLoginOnly() + client := login.Client() - mode := ctx.String("mode") - org := ctx.String("org") - user := ctx.String("user") - - var rps []*gitea.Repository - var err error - - if org != "" { - rps, _, err = login.Client().ListOrgRepos(org, gitea.ListOrgReposOptions{}) - } else if user != "" { - rps, _, err = login.Client().ListUserRepos(user, gitea.ListReposOptions{}) + var ownerID int64 + if ctx.IsSet("owner") { + // test if owner is a organisation + org, resp, err := client.GetOrg(ctx.String("owner")) + if err != nil { + if resp == nil || resp.StatusCode != http.StatusNotFound { + return err + } + // if owner is no org, its a user + user, _, err := client.GetUserInfo(ctx.String("owner")) + if err != nil { + return err + } + ownerID = user.ID + } else { + ownerID = org.ID + } } else { - rps, _, err = login.Client().ListMyRepos(gitea.ListReposOptions{}) + me, _, err := client.GetMyUserInfo() + if err != nil { + return err + } + ownerID = me.ID } + + var isArchived *bool + if ctx.IsSet("archived") { + archived := strings.ToLower(ctx.String("archived"))[:1] == "t" + isArchived = &archived + } + + var isPrivate *bool + if ctx.IsSet("private") { + private := strings.ToLower(ctx.String("private"))[:1] == "t" + isArchived = &private + } + + mode := gitea.RepoTypeNone + switch ctx.String("mode") { + case "fork": + mode = gitea.RepoTypeFork + case "mirror": + mode = gitea.RepoTypeMirror + case "source": + mode = gitea.RepoTypeSource + } + + rps, _, err := client.SearchRepos(gitea.SearchRepoOptions{ + OwnerID: ownerID, + IsPrivate: isPrivate, + IsArchived: isArchived, + Type: mode, + }) if err != nil { - log.Fatal(err) - } - - var repos []*gitea.Repository - if mode == "" { - repos = rps - } else if mode == "fork" { - for _, rp := range rps { - if rp.Fork == true { - repos = append(repos, rp) - } - } - } else if mode == "mirror" { - for _, rp := range rps { - if rp.Mirror == true { - repos = append(repos, rp) - } - } - } else if mode == "source" { - for _, rp := range rps { - if rp.Mirror != true && rp.Fork != true { - repos = append(repos, rp) - } - } - } else { - log.Fatal("Unknown mode: ", mode, "\nUse one of the following:\n- fork\n- mirror\n- source\n") - return nil + return err } if len(rps) == 0 { @@ -107,7 +211,7 @@ func runReposList(ctx *cli.Context) error { } var values [][]string - for _, rp := range repos { + for _, rp := range rps { var mode = "source" if rp.Fork { mode = "fork" @@ -130,3 +234,80 @@ func runReposList(ctx *cli.Context) error { return nil } + +func runRepoDetail(_ *cli.Context, path string) error { + login := initCommandLoginOnly() + client := login.Client() + repoOwner, repoName := getOwnerAndRepo(path, login.User) + repo, _, err := client.GetRepo(repoOwner, repoName) + if err != nil { + return err + } + topics, _, err := client.ListRepoTopics(repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{}) + if err != nil { + return err + } + + output := repo.FullName + if repo.Mirror { + output += " (mirror)" + } + if repo.Fork { + output += " (fork)" + } + if repo.Archived { + output += " (archived)" + } + if repo.Empty { + output += " (empty)" + } + output += "\n" + if len(topics) != 0 { + output += "Topics: " + strings.Join(topics, ", ") + "\n" + } + output += "\n" + output += repo.Description + "\n\n" + output += fmt.Sprintf( + "Open Issues: %d, Stars: %d, Forks: %d, Size: %s\n\n", + repo.OpenIssues, + repo.Stars, + repo.Forks, + utils.FormatSize(int64(repo.Size)), + ) + + fmt.Print(output) + return nil +} + +func runRepoCreate(ctx *cli.Context) error { + login := initCommandLoginOnly() + client := login.Client() + var ( + repo *gitea.Repository + err error + ) + opts := gitea.CreateRepoOption{ + Name: ctx.String("name"), + Description: ctx.String("description"), + Private: ctx.Bool("private"), + AutoInit: ctx.Bool("init"), + IssueLabels: ctx.String("labels"), + Gitignores: ctx.String("gitignores"), + License: ctx.String("license"), + Readme: ctx.String("readme"), + DefaultBranch: ctx.String("branch"), + } + if len(ctx.String("owner")) != 0 { + repo, _, err = client.CreateOrgRepo(ctx.String("owner"), opts) + } else { + repo, _, err = client.CreateRepo(opts) + } + if err != nil { + return err + } + if err = runRepoDetail(ctx, repo.FullName); err != nil { + return err + } + fmt.Printf("%s\n", repo.HTMLURL) + return nil +} diff --git a/modules/utils/format.go b/modules/utils/format.go new file mode 100644 index 0000000..9435119 --- /dev/null +++ b/modules/utils/format.go @@ -0,0 +1,23 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package utils + +import "fmt" + +// FormatSize get kb in int and return string +func FormatSize(kb int64) string { + if kb < 1024 { + return fmt.Sprintf("%d Kb", kb) + } + mb := kb / 1024 + if mb < 1024 { + return fmt.Sprintf("%d Mb", mb) + } + gb := mb / 1024 + if gb < 1024 { + return fmt.Sprintf("%d Gb", gb) + } + return fmt.Sprintf("%d Tb", gb/1024) +}