feat!: rebuild tea on Cobra with explicit noun/verb commands (#1126)

- **switch tea to the Cobra command tree:** `internal/app` wires the packages from parts 1–4 into explicit noun/verb commands with `--repo`, `--json` / `--jq`, `--sudo` and `--debug`; `main.go` points at it. Build, release and docs tooling (`tools/cli-docs`, Makefile, goreleaser, snap, CI) and README / CONTRIBUTING are updated.
- **remove the urfave/cli command tree:** deletes `cmd/`, `modules/`, the old integration tests, contrib completion scripts and the generated `docs/CLI.md`, and drops their dependencies. This commit only deletes.

## Breaking changes

This is a breaking release. It requires Gitea 28 or newer; configuration moves to separate `config.yml` and `hosts.yml` files and requires fresh authentication, and command names, aliases, flags and output formats change. `docs/migration-1.0.md` maps every old command, flag and environment variable to its replacement.

## Issues

fixes #1118
fixes #1116
fixes #1115
fixes #1094
fixes #1091
fixes #1073
fixes #1052
fixes #1032
fixes #1023
fixes #966
fixes #908
fixes #833
fixes #831
fixes #817
fixes #804
fixes #779
fixes #770
fixes #737
fixes #697
fixes #726
fixes #677
fixes #672
fixes #633
fixes #632
fixes #560
fixes #556
fixes #523
fixes #516
fixes #510
fixes #504
fixes #500
fixes #482
fixes #406
fixes #403
fixes #373
fixes #351
fixes #344
fixes #326
fixes #325
fixes #323
fixes #246
fixes #240
fixes #232
fixes #197
fixes #172
fixes #141
fixes #69
fixes #1110
fixes #569
fixes #480
fixes #666
fixes #670
fixes #457
fixes #643
fixes #498
fixes #490
fixes #1069
fixes #834
fixes #602
fixes #328
fixes #417
fixes #571
fixes #1029
fixes #489
fixes #1050
fixes #162
fixes #430
fixes #1087
fixes #683

Reviewed-on: https://gitea.com/gitea/tea/pulls/1126
Reviewed-by: TheFox0x7 <95654+thefox0x7@noreply.gitea.com>
This commit is contained in:
bircni committed 2026-10-11 17:23:06 +00:00
1 parent 12e415a7a7
commit f02245449b
456 files changed
+18892 -34015

No files matched your search

-160
View File
@@ -1,160 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
stdctx "context"
"fmt"
"gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3"
)
// 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",
ArgsUsage: " ", // command does not accept arguments
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)",
},
&cli.BoolFlag{
Name: "template",
Usage: "make repo a template repo",
},
&cli.StringFlag{
Name: "trustmodel",
Usage: "select trust model (committer,collaborator,collaborator+committer)",
},
&cli.StringFlag{
Name: "object-format",
Required: false,
Usage: "select git object format (sha1,sha256)",
Validator: func(v string) error {
if v != "sha1" && v != "sha256" {
return fmt.Errorf("invalid object format '%s', must be either 'sha1' or 'sha256'", v)
}
return nil
},
},
}, flags.LoginOutputFlags...),
}
func runRepoCreate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := ctx.Login.Client()
var (
repo *gitea.Repository
trustmodel gitea.TrustModel
)
if ctx.IsSet("trustmodel") {
switch ctx.String("trustmodel") {
case "committer":
trustmodel = gitea.TrustModelCommitter
case "collaborator":
trustmodel = gitea.TrustModelCollaborator
case "collaborator+committer":
trustmodel = gitea.TrustModelCollaboratorCommitter
default:
return fmt.Errorf("unknown trustmodel type '%s'", ctx.String("trustmodel"))
}
}
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"),
Template: ctx.Bool("template"),
TrustModel: trustmodel,
ObjectFormatName: ctx.String("object-format"),
}
if len(ctx.String("owner")) != 0 {
repo, _, err = client.Repositories.CreateOrgRepo(requestCtx, ctx.String("owner"), opts)
} else {
repo, _, err = client.Repositories.CreateRepo(requestCtx, opts)
}
if err != nil {
return err
}
topics, _, err := client.Repositories.ListRepoTopics(requestCtx, repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}
-125
View File
@@ -1,125 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
"fmt"
stdctx "context"
"gitea.dev/sdk"
"github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"gitea.dev/tea/modules/utils"
)
// CmdRepoCreateFromTemplate represents a sub command of repos to generate one from a template repo
var CmdRepoCreateFromTemplate = cli.Command{
Name: "create-from-template",
Aliases: []string{"ct"},
Usage: "Create a repository based on an existing template",
Description: "Create a repository based on an existing template",
Action: runRepoCreateFromTemplate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "template",
Aliases: []string{"t"},
Required: true,
Usage: "source template to copy from",
},
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Required: true,
Usage: "name of new repo",
},
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Usage: "name of repo owner",
},
&cli.BoolFlag{
Name: "private",
Usage: "make new repo private",
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"desc"},
Usage: "add custom description to repo",
},
&cli.BoolFlag{
Name: "content",
Value: true,
Usage: "copy git content from template",
},
&cli.BoolFlag{
Name: "githooks",
Value: true,
Usage: "copy git hooks from template",
},
&cli.BoolFlag{
Name: "avatar",
Value: true,
Usage: "copy repo avatar from template",
},
&cli.BoolFlag{
Name: "labels",
Value: true,
Usage: "copy repo labels from template",
},
&cli.BoolFlag{
Name: "topics",
Value: true,
Usage: "copy topics from template",
},
&cli.BoolFlag{
Name: "webhooks",
Usage: "copy webhooks from template",
},
}, flags.LoginOutputFlags...),
}
func runRepoCreateFromTemplate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := ctx.Login.Client()
templateOwner, templateRepo := utils.GetOwnerAndRepo(ctx.String("template"), ctx.Login.User)
owner := ctx.Login.User
if ctx.IsSet("owner") {
owner = ctx.String("owner")
}
opts := gitea.CreateRepoFromTemplateOption{
Name: ctx.String("name"),
Owner: owner,
Description: ctx.String("description"),
Private: ctx.Bool("private"),
GitContent: ctx.Bool("content"),
GitHooks: ctx.Bool("githooks"),
Avatar: ctx.Bool("avatar"),
Labels: ctx.Bool("labels"),
Topics: ctx.Bool("topics"),
Webhooks: ctx.Bool("webhooks"),
}
repo, _, err := client.Repositories.CreateRepoFromTemplate(requestCtx, templateOwner, templateRepo, opts)
if err != nil {
return err
}
topics, _, err := client.Repositories.ListRepoTopics(requestCtx, repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}
-89
View File
@@ -1,89 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
stdctx "context"
"fmt"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"charm.land/huh/v2"
"github.com/urfave/cli/v3"
)
// CmdRepoRm represents a sub command of repos to delete an existing repo
var CmdRepoRm = cli.Command{
Name: "delete",
Aliases: []string{"rm"},
Usage: "Delete an existing repository",
Description: "Removes a repository from your Gitea instance",
ArgsUsage: " ", // command does not accept arguments
Action: runRepoDelete,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "name",
Aliases: []string{""},
Required: true,
Usage: "name of the repo",
},
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Required: false,
Usage: "owner of the repo",
},
&cli.BoolFlag{
Name: "force",
Aliases: []string{"f"},
Required: false,
Value: false,
Usage: "Force the deletion and don't ask for confirmation",
},
}, flags.LoginOutputFlags...),
}
func runRepoDelete(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := ctx.Login.Client()
var owner string
if ctx.IsSet("owner") {
owner = ctx.String("owner")
} else {
owner = ctx.Login.User
}
repoName := ctx.String("name")
repoSlug := fmt.Sprintf("%s/%s", owner, repoName)
if !ctx.Bool("force") {
var enteredRepoSlug string
if err := huh.NewInput().
Title(fmt.Sprintf("Confirm the deletion of the repository '%s' by typing its name: ", repoSlug)).
Validate(huh.ValidateNotEmpty()).
Value(&enteredRepoSlug).
Run(); err != nil {
return err
}
if enteredRepoSlug != repoSlug {
return fmt.Errorf("entered wrong repository name '%s', expected '%s'", enteredRepoSlug, repoSlug)
}
}
_, err = client.Repositories.DeleteRepo(requestCtx, owner, repoName)
if err != nil {
return err
}
fmt.Printf("Successfully deleted %s/%s\n", owner, repoName)
return nil
}
-111
View File
@@ -1,111 +0,0 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
stdctx "context"
"strings"
"gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3"
)
// CmdRepoEdit represents a sub command of repos to edit one
var CmdRepoEdit = cli.Command{
Name: "edit",
Aliases: []string{"e"},
Usage: "Edit repository properties",
Description: "Edit repository properties",
ArgsUsage: " ", // command does not accept arguments
Action: runRepoEdit,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "New name of the repository",
},
&cli.StringFlag{
Name: "description",
Aliases: []string{"desc"},
Usage: "New description of the repository",
},
&cli.StringFlag{
Name: "website",
Usage: "New website URL of the repository",
},
&cli.StringFlag{
Name: "private",
Usage: "Set private [true/false]",
DefaultText: "true",
},
&cli.StringFlag{
Name: "template",
Usage: "Set template [true/false]",
DefaultText: "true",
},
&cli.StringFlag{
Name: "archived",
Usage: "Set archived [true/false]",
DefaultText: "true",
},
&cli.StringFlag{
Name: "default-branch",
Usage: "Set default branch",
},
}, flags.AllDefaultFlags...),
}
func runRepoEdit(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
client := ctx.Login.Client()
opts := gitea.EditRepoOption{}
if ctx.IsSet("name") {
val := ctx.String("name")
opts.Name = &val
}
if ctx.IsSet("description") {
val := ctx.String("description")
opts.Description = &val
}
if ctx.IsSet("website") {
val := ctx.String("website")
opts.Website = &val
}
if ctx.IsSet("default-branch") {
val := ctx.String("default-branch")
opts.DefaultBranch = &val
}
if ctx.IsSet("private") {
opts.Private = gitea.OptionalBool(strings.ToLower(ctx.String("private"))[:1] == "t")
}
if ctx.IsSet("template") {
opts.Template = gitea.OptionalBool(strings.ToLower(ctx.String("template"))[:1] == "t")
}
if ctx.IsSet("archived") {
opts.Archived = gitea.OptionalBool(strings.ToLower(ctx.String("archived"))[:1] == "t")
}
repo, _, err := client.Repositories.EditRepo(requestCtx, ctx.Owner, ctx.Repo, opts)
if err != nil {
return err
}
topics, _, err := client.Repositories.ListRepoTopics(requestCtx, repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
return nil
}
-36
View File
@@ -1,36 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
"fmt"
"gitea.dev/sdk"
"github.com/urfave/cli/v3"
)
var typeFilterFlag = cli.StringFlag{
Name: "type",
Aliases: []string{"T"},
Required: false,
Usage: "Filter by type: fork, mirror, source",
}
func getTypeFilter(cmd *cli.Command) (filter gitea.RepoType, err error) {
t := cmd.String("type")
filter = gitea.RepoTypeNone
switch t {
case "":
filter = gitea.RepoTypeNone
case "fork":
filter = gitea.RepoTypeFork
case "mirror":
filter = gitea.RepoTypeMirror
case "source":
filter = gitea.RepoTypeSource
default:
err = fmt.Errorf("invalid repo type '%s'. valid: fork, mirror, source", t)
}
return
}
-64
View File
@@ -1,64 +0,0 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
stdctx "context"
"fmt"
"gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3"
)
// CmdRepoFork represents a sub command of repos to fork an existing repo
var CmdRepoFork = cli.Command{
Name: "fork",
Aliases: []string{"f"},
Usage: "Fork an existing repository",
Description: "Create a repository from an existing repo",
ArgsUsage: " ", // command does not accept arguments
Action: runRepoFork,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Usage: "name of fork's owner, defaults to current user",
},
}, flags.LoginRepoFlags...),
}
func runRepoFork(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
if err := ctx.Ensure(context.CtxRequirement{RemoteRepo: true}); err != nil {
return err
}
client := ctx.Login.Client()
opts := gitea.CreateForkOption{}
if ctx.IsSet("owner") {
owner := ctx.String("owner")
opts.Organization = &owner
}
repo, _, err := client.Repositories.CreateFork(requestCtx, ctx.Owner, ctx.Repo, opts)
if err != nil {
return err
}
topics, _, err := client.Repositories.ListRepoTopics(requestCtx, repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}
-187
View File
@@ -1,187 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
stdctx "context"
"fmt"
"net/http"
"gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3"
)
var repoFieldsFlag = flags.FieldsFlag(print.RepoFields, []string{
"owner", "name", "type", "ssh",
})
// CmdReposListFlags contains all flags needed for repo listing
var CmdReposListFlags = append([]cli.Flag{
&cli.BoolFlag{
Name: "watched",
Aliases: []string{"w"},
Required: false,
Usage: "List your watched repos instead",
},
&cli.BoolFlag{
Name: "starred",
Aliases: []string{"s"},
Required: false,
Usage: "List your starred repos instead",
},
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Required: false,
Usage: "List repos of a specific owner (org or user)",
},
repoFieldsFlag,
&typeFilterFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.LoginOutputFlags...)
// CmdReposList represents a sub command of repos to list them
var CmdReposList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List repositories you have access to",
Description: "List repositories you have access to",
Action: RunReposList,
Flags: CmdReposListFlags,
}
// RunReposList list repositories
func RunReposList(requestCtx stdctx.Context, cmd *cli.Command) error {
teaCmd, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := teaCmd.Login.Client()
typeFilter, err := getTypeFilter(cmd)
if err != nil {
return err
}
var rps []*gitea.Repository
if owner := teaCmd.String("owner"); owner != "" {
var err error
_, resp, orgErr := client.Organizations.GetOrg(requestCtx, owner)
if orgErr != nil {
if resp == nil || resp.StatusCode != http.StatusNotFound {
return fmt.Errorf("could not find owner: %w", orgErr)
}
// not an org, treat as user
rps, _, err = client.Repositories.ListUserRepos(requestCtx, owner, gitea.ListReposOptions{
ListOptions: flags.GetListOptions(cmd),
})
} else {
rps, _, err = client.Repositories.ListOrgRepos(requestCtx, owner, gitea.ListOrgReposOptions{
ListOptions: flags.GetListOptions(cmd),
})
}
if err != nil {
return err
}
} else if teaCmd.Bool("starred") {
user, _, err := client.Users.GetMyUserInfo(requestCtx)
if err != nil {
return err
}
rps, _, err = client.Repositories.SearchRepos(requestCtx, gitea.SearchRepoOptions{
ListOptions: flags.GetListOptions(cmd),
StarredByUserID: user.ID,
})
if err != nil {
return err
}
} else if teaCmd.Bool("watched") {
// GetMyWatchedRepos doesn't expose server-side pagination,
// so we implement client-side pagination as a workaround
allRepos, _, err := client.Repositories.GetMyWatchedRepos(requestCtx)
if err != nil {
return err
}
rps = paginateRepos(allRepos, flags.GetListOptions(cmd))
} else {
var err error
rps, _, err = client.Repositories.ListMyRepos(requestCtx, gitea.ListReposOptions{
ListOptions: flags.GetListOptions(cmd),
})
if err != nil {
return err
}
}
reposFiltered := rps
if typeFilter != gitea.RepoTypeNone {
reposFiltered = filterReposByType(rps, typeFilter)
}
fields, err := repoFieldsFlag.GetValues(cmd)
if err != nil {
return err
}
return print.ReposList(reposFiltered, teaCmd.Output, fields)
}
func filterReposByType(repos []*gitea.Repository, t gitea.RepoType) []*gitea.Repository {
var filtered []*gitea.Repository
for _, r := range repos {
switch t {
case gitea.RepoTypeFork:
if !r.Fork {
continue
}
case gitea.RepoTypeMirror:
if !r.Mirror {
continue
}
case gitea.RepoTypeSource:
if r.Fork || r.Mirror {
continue
}
}
filtered = append(filtered, r)
}
return filtered
}
// paginateRepos implements client-side pagination for repositories.
// This is a workaround for API endpoints that don't support server-side pagination.
func paginateRepos(repos []*gitea.Repository, opts gitea.ListOptions) []*gitea.Repository {
if len(repos) == 0 {
return repos
}
pageSize := opts.PageSize
if pageSize <= 0 {
pageSize = flags.PaginationLimitFlag.Value
}
page := opts.Page
if page < 1 {
page = 1
}
start := (page - 1) * pageSize
end := start + pageSize
if start >= len(repos) {
return []*gitea.Repository{}
}
if end > len(repos) {
end = len(repos)
}
return repos[start:end]
}
-175
View File
@@ -1,175 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
"fmt"
stdctx "context"
"gitea.dev/sdk"
"github.com/urfave/cli/v3"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
)
// CmdRepoMigrate represents a sub command of repos to migrate one
var CmdRepoMigrate = cli.Command{
Name: "migrate",
Aliases: []string{"m"},
Usage: "Migrate a repository",
Description: "Migrate a repository and or mirror it.",
ArgsUsage: " ", // command does not accept arguments
Action: runRepoMigrate,
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "Name of the repository",
Required: true,
},
&cli.StringFlag{
Name: "owner",
Usage: "Owner of the repository",
Required: true,
},
&cli.StringFlag{
Name: "clone-url",
Usage: "Clone URL of the repository",
Required: true,
},
&cli.StringFlag{
Name: "service",
Usage: string("Service to migrate from. Supported services are: " + gitea.GitServicePlain +
", " + gitea.GitServiceGitea + ", " + gitea.GitServiceGitlab + ", " + gitea.GitServiceGogs),
Required: true,
},
&cli.BoolFlag{
Name: "mirror",
Usage: "Mirror the repository",
},
&cli.BoolFlag{
Name: "private",
Usage: "Make the repository private",
},
&cli.BoolFlag{
Name: "template",
Usage: "Make the repository a template",
},
&cli.BoolFlag{
Name: "wiki",
Usage: "Copy the wiki",
},
&cli.BoolFlag{
Name: "issues",
Usage: "Copy the issues",
},
&cli.BoolFlag{
Name: "labels",
Usage: "Copy the lables",
},
&cli.BoolFlag{
Name: "pull-requests",
Usage: "Copy the pull requests",
},
&cli.BoolFlag{
Name: "releases",
Usage: "Copy the releases",
},
&cli.BoolFlag{
Name: "milestones",
Usage: "Copy the milestones",
},
&cli.StringFlag{
Name: "mirror-interval",
Usage: "Interval to mirror the repository.",
},
&cli.BoolFlag{
Name: "lfs",
Usage: "Copy the LFS objects",
},
&cli.StringFlag{
Name: "lfs-endpoint",
Usage: "LFS endpoint to use",
},
&cli.StringFlag{
Name: "auth-user",
Usage: "Username to use for authentication.",
},
&cli.StringFlag{
Name: "auth-password",
Usage: "Password to use for authentication.",
},
&cli.StringFlag{
Name: "auth-token",
Usage: "Token to use for authentication.",
},
}, flags.LoginOutputFlags...),
}
func runRepoMigrate(requestCtx stdctx.Context, cmd *cli.Command) error {
ctx, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := ctx.Login.Client()
var (
repo *gitea.Repository
service gitea.GitServiceType
)
if ctx.IsSet("service") {
switch ctx.String("service") {
case "git":
service = gitea.GitServicePlain
case "gitea":
service = gitea.GitServiceGitea
case "gitlab":
service = gitea.GitServiceGitlab
case "gogs":
service = gitea.GitServiceGogs
case "github":
service = gitea.GitServiceGithub
default:
return fmt.Errorf("unknown git service type '%s'", ctx.String("service"))
}
}
opts := gitea.MigrateRepoOption{
RepoName: ctx.String("name"),
RepoOwner: ctx.String("owner"),
CloneAddr: ctx.String("clone-url"),
Service: service,
AuthUsername: ctx.String("auth-user"),
AuthPassword: ctx.String("auth-password"),
AuthToken: ctx.String("auth-token"),
Mirror: ctx.Bool("mirror"),
Private: ctx.Bool("private"),
Description: ctx.String("description"),
Wiki: ctx.Bool("wiki"),
Milestones: ctx.Bool("milestones"),
Labels: ctx.Bool("labels"),
Issues: ctx.Bool("issues"),
PullRequests: ctx.Bool("pull-requests"),
Releases: ctx.Bool("releases"),
MirrorInterval: ctx.String("mirror-interval"),
LFS: ctx.Bool("lfs"),
LFSEndpoint: ctx.String("lfs-endpoint"),
}
repo, _, err = client.Repositories.MigrateRepo(requestCtx, opts)
if err != nil {
return err
}
topics, _, err := client.Repositories.ListRepoTopics(requestCtx, repo.Owner.UserName, repo.Name, gitea.ListRepoTopicsOptions{})
if err != nil {
return err
}
print.RepoDetails(repo, topics)
fmt.Printf("%s\n", repo.HTMLURL)
return nil
}
-134
View File
@@ -1,134 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repos
import (
stdctx "context"
"fmt"
"net/http"
"strings"
"gitea.dev/sdk"
"gitea.dev/tea/cmd/flags"
"gitea.dev/tea/modules/context"
"gitea.dev/tea/modules/print"
"github.com/urfave/cli/v3"
)
// CmdReposSearch represents a sub command of repos to find them
var CmdReposSearch = cli.Command{
Name: "search",
Aliases: []string{"s"},
Usage: "Find any repo on an Gitea instance",
Description: "Find any repo on an Gitea instance",
ArgsUsage: "[<search term>]",
Action: runReposSearch,
Flags: append([]cli.Flag{
&cli.BoolFlag{
// TODO: it might be nice to search for topics as an ADDITIONAL filter.
// for that, we'd probably need to make multiple queries and UNION the results.
Name: "topic",
Aliases: []string{"t"},
Required: false,
Usage: "Search for term in repo topics instead of name",
},
&typeFilterFlag,
&cli.StringFlag{
Name: "owner",
Aliases: []string{"O"},
Required: false,
Usage: "Filter by owner",
},
&cli.StringFlag{
Name: "private",
Required: false,
Usage: "Filter private repos (true|false)",
},
&cli.StringFlag{
Name: "archived",
Required: false,
Usage: "Filter archived repos (true|false)",
},
repoFieldsFlag,
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.LoginOutputFlags...),
}
func runReposSearch(requestCtx stdctx.Context, cmd *cli.Command) error {
teaCmd, err := context.InitCommand(cmd)
if err != nil {
return err
}
client := teaCmd.Login.Client()
var ownerID int64
if teaCmd.IsSet("owner") {
// test if owner is an organization
org, resp, err := client.Organizations.GetOrg(requestCtx, teaCmd.String("owner"))
if err != nil {
if resp == nil || resp.StatusCode != http.StatusNotFound {
return fmt.Errorf("could not find owner: %w", err)
}
// if owner is no org, its a user
user, _, err := client.Users.GetUserInfo(requestCtx, teaCmd.String("owner"))
if err != nil {
return err
}
ownerID = user.ID
} else {
ownerID = org.ID
}
}
var isArchived *bool
if teaCmd.IsSet("archived") {
archived := strings.ToLower(teaCmd.String("archived"))[:1] == "t"
isArchived = &archived
}
var isPrivate *bool
if teaCmd.IsSet("private") {
private := strings.ToLower(teaCmd.String("private"))[:1] == "t"
isPrivate = &private
}
mode, err := getTypeFilter(cmd)
if err != nil {
return err
}
var keyword string
if teaCmd.Args().Present() {
keyword = strings.Join(teaCmd.Args().Slice(), " ")
}
user, _, err := client.Users.GetMyUserInfo(requestCtx)
if err != nil {
return err
}
rps, _, err := client.Repositories.SearchRepos(requestCtx, gitea.SearchRepoOptions{
ListOptions: flags.GetListOptions(cmd),
OwnerID: ownerID,
IsPrivate: isPrivate,
IsArchived: isArchived,
Type: mode,
Keyword: keyword,
KeywordInDescription: true,
KeywordIsTopic: teaCmd.Bool("topic"),
PrioritizedByOwnerID: user.ID,
})
if err != nil {
return err
}
fields, err := repoFieldsFlag.GetValues(cmd)
if err != nil {
return err
}
return print.ReposList(rps, teaCmd.Output, fields)
}