mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
revert: tea 1.0 rewrite (#1122–#1126) (#1146)
Reverts #1126, #1125, #1124, #1123 and #1122. `go.mod` keeps the Go 1.26 line with toolchain `go1.26.9` (instead of the original `go1.26.6`) so the security fix from #1131 isn't lost. reopens #69 reopens #141 reopens #162 reopens #172 reopens #197 reopens #232 reopens #240 reopens #246 reopens #323 reopens #325 reopens #326 reopens #328 reopens #344 reopens #351 reopens #373 reopens #403 reopens #406 reopens #417 reopens #430 reopens #457 reopens #480 reopens #482 reopens #489 reopens #490 reopens #498 reopens #500 reopens #504 reopens #510 reopens #516 reopens #523 reopens #556 reopens #560 reopens #569 reopens #571 reopens #602 reopens #632 reopens #633 reopens #643 reopens #666 reopens #670 reopens #672 reopens #677 reopens #683 reopens #697 reopens #726 reopens #737 reopens #770 reopens #779 reopens #804 reopens #817 reopens #831 reopens #833 reopens #834 reopens #908 reopens #966 reopens #1023 reopens #1029 reopens #1032 reopens #1050 reopens #1052 reopens #1069 reopens #1073 reopens #1087 reopens #1091 reopens #1094 reopens #1110 reopens #1115 reopens #1116 reopens #1118 Reviewed-on: https://gitea.com/gitea/tea/pulls/1146 Reviewed-by: TheFox0x7 <95654+thefox0x7@noreply.gitea.com>
This commit is contained in:
1 parent
33bb12729e
commit
c5f674111a
604 files changed
+33711
-35545
No files matched your search
@@ -0,0 +1,160 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
// 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]
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
// 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
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// 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)
|
||||
}
|
||||
Reference in new issue
Block a user