From 2e701ee8a2af230945f36096005ecbe6e5c8849f Mon Sep 17 00:00:00 2001 From: 6543 <6543@noreply.gitea.io> Date: Wed, 23 Sep 2020 19:49:59 +0000 Subject: [PATCH] Add Repo Create subcomand & enhancements (#173) repos ls: use owner filter and remove org&user one better desc refactor rm local filter, let us fix upstream split user org add archive and private filters use SearchRepos migrate to sdk v0.13.0 print URL add CmdRepoCreate, Add RepoDetails ListRepos: better desc, add aliases, add note for sdk-release Co-authored-by: 6543 <6543@obermui.de> Reviewed-on: https://gitea.com/gitea/tea/pulls/173 Reviewed-by: Andrew Thornton Reviewed-by: Norwin --- cmd/repos.go | 283 ++++++++++++++++++++++++++++++++-------- modules/utils/format.go | 23 ++++ 2 files changed, 255 insertions(+), 51 deletions(-) create mode 100644 modules/utils/format.go 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) +}