mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
refactor(repo,org,team,release): trim help texts, obvious comments and single-use helpers
Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
11 files changed
+55
-129
No files matched your search
@@ -21,11 +21,7 @@ func (a *application) adminCommand() *cobra.Command {
|
|||||||
group := &cobra.Command{Use: "admin", Short: "Manage instance administration", Long: "Administer the Gitea instance. These commands need an administrator account."}
|
group := &cobra.Command{Use: "admin", Short: "Manage instance administration", Long: "Administer the Gitea instance. These commands need an administrator account."}
|
||||||
users := &cobra.Command{Use: "user", Short: "Manage registered accounts", Long: `List, view, create, edit and delete the accounts of the instance. These commands need an
|
users := &cobra.Command{Use: "user", Short: "Manage registered accounts", Long: `List, view, create, edit and delete the accounts of the instance. These commands need an
|
||||||
administrator account.`}
|
administrator account.`}
|
||||||
users.AddCommand(a.adminUserListCommand(), a.adminUserViewCommand())
|
users.AddCommand(a.adminUserListCommand(), a.adminUserViewCommand(), a.adminUserChangeCommand("create"), a.adminUserChangeCommand("edit"), a.adminUserDeleteCommand())
|
||||||
for _, verb := range []string{"create", "edit"} {
|
|
||||||
users.AddCommand(a.adminUserChangeCommand(verb))
|
|
||||||
}
|
|
||||||
users.AddCommand(a.adminUserDeleteCommand())
|
|
||||||
group.AddCommand(users)
|
group.AddCommand(users)
|
||||||
return group
|
return group
|
||||||
}
|
}
|
||||||
@@ -149,7 +145,6 @@ $ tea admin user view bob --json email,admin`,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// adminUserChangeCommand creates or edits an account.
|
|
||||||
func (a *application) adminUserChangeCommand(verb string) *cobra.Command {
|
func (a *application) adminUserChangeCommand(verb string) *cobra.Command {
|
||||||
var username, email, fullName, description, website, location, visibility, password, passwordFile string
|
var username, email, fullName, description, website, location, visibility, password, passwordFile string
|
||||||
var admin, active, restricted, prohibitLogin, mustChangePassword, allowGitHook, allowImportLocal, allowCreateOrganization bool
|
var admin, active, restricted, prohibitLogin, mustChangePassword, allowGitHook, allowImportLocal, allowCreateOrganization bool
|
||||||
@@ -330,9 +325,8 @@ func (a *application) adminUserDeleteCommand() *cobra.Command {
|
|||||||
var purge bool
|
var purge bool
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "delete <username>", Short: "Delete an account", Args: argsExact(1), ValidArgsFunction: a.completeAdminUsers(),
|
Use: "delete <username>", Short: "Delete an account", Args: argsExact(1), ValidArgsFunction: a.completeAdminUsers(),
|
||||||
Long: `Delete an account. Gitea refuses while the user owns repositories or is the last owner of an
|
Long: `Delete an account. Gitea refuses while the user owns repositories or organizations, unless
|
||||||
organization: transfer or delete those first, or pass --purge to delete the account with
|
--purge deletes the account with everything it owns.`,
|
||||||
everything it owns. A purge cannot be undone, so a terminal asks you to type the username.`,
|
|
||||||
Example: `$ tea admin user delete spammer
|
Example: `$ tea admin user delete spammer
|
||||||
# also delete the user's repositories, packages and organization memberships
|
# also delete the user's repositories, packages and organization memberships
|
||||||
$ tea admin user delete spammer --purge`,
|
$ tea admin user delete spammer --purge`,
|
||||||
|
|||||||
+11
-26
@@ -18,23 +18,17 @@ import (
|
|||||||
|
|
||||||
// validateBranch rejects invalid Git refs before making requests.
|
// validateBranch rejects invalid Git refs before making requests.
|
||||||
func validateBranch(name string) error {
|
func validateBranch(name string) error {
|
||||||
if name == "" || name == "@" || strings.HasPrefix(name, "-") || strings.HasPrefix(name, "/") || strings.HasSuffix(name, "/") || strings.HasSuffix(name, ".") || strings.Contains(name, "..") || strings.Contains(name, "@{") || strings.Contains(name, "//") || strings.ContainsAny(name, " ~^:?*[\\\t\r\n") {
|
invalid := name == "" || name == "@" || strings.HasPrefix(name, "-") || strings.HasPrefix(name, "/") || strings.HasSuffix(name, "/") || strings.HasSuffix(name, ".") || strings.Contains(name, "..") || strings.Contains(name, "@{") || strings.Contains(name, "//") || strings.ContainsAny(name, " ~^:?*[\\\t\r\n") ||
|
||||||
return clierr.Wrap(clierr.Usage, errors.New("invalid branch name"))
|
strings.ContainsFunc(name, func(r rune) bool { return r < 32 || r == 127 })
|
||||||
}
|
|
||||||
for part := range strings.SplitSeq(name, "/") {
|
for part := range strings.SplitSeq(name, "/") {
|
||||||
if strings.HasPrefix(part, ".") || strings.HasSuffix(part, ".lock") {
|
invalid = invalid || strings.HasPrefix(part, ".") || strings.HasSuffix(part, ".lock")
|
||||||
|
}
|
||||||
|
if invalid {
|
||||||
return clierr.Wrap(clierr.Usage, errors.New("invalid branch name"))
|
return clierr.Wrap(clierr.Usage, errors.New("invalid branch name"))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
for _, r := range name {
|
|
||||||
if r < 32 || r == 127 {
|
|
||||||
return clierr.Wrap(clierr.Usage, errors.New("invalid branch name"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateBranches validates every branch name.
|
|
||||||
func validateBranches(names []string) error {
|
func validateBranches(names []string) error {
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if err := validateBranch(name); err != nil {
|
if err := validateBranch(name); err != nil {
|
||||||
@@ -249,7 +243,10 @@ $ tea branch delete old-a old-b --yes`,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
subject := branchSubject(args)
|
subject := "branch " + args[0]
|
||||||
|
if len(args) > 1 {
|
||||||
|
subject = fmt.Sprintf("%d branches (%s)", len(args), strings.Join(args, ", "))
|
||||||
|
}
|
||||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + target.Repo + "?"}); err != nil {
|
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + target.Repo + "?"}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -263,14 +260,6 @@ $ tea branch delete old-a old-b --yes`,
|
|||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
// branchSubject names one or more branches in a prompt: "branch main" or "2 branches (a, b)".
|
|
||||||
func branchSubject(names []string) string {
|
|
||||||
if len(names) == 1 {
|
|
||||||
return "branch " + names[0]
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%d branches (%s)", len(names), strings.Join(names, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *application) branchProtectCommand() *cobra.Command {
|
func (a *application) branchProtectCommand() *cobra.Command {
|
||||||
var rule services.Protection
|
var rule services.Protection
|
||||||
var pattern string
|
var pattern string
|
||||||
@@ -278,12 +267,8 @@ func (a *application) branchProtectCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "protect <branch>...",
|
Use: "protect <branch>...",
|
||||||
Short: "Protect branches",
|
Short: "Protect branches",
|
||||||
Long: `Add a protection rule for each branch. By default nobody can push to a protected branch directly
|
Long: `Add a protection rule for each existing branch, or with --pattern for every branch matching a
|
||||||
and pull requests need one approving review to merge; --allow-push lets users or teams push, and
|
glob. By default nobody can push directly and pull requests need one approving review.`,
|
||||||
--required-approvals changes the review count.
|
|
||||||
|
|
||||||
The branches must exist. --pattern protects every branch that matches a glob instead, such as
|
|
||||||
release/*, including branches created later.`,
|
|
||||||
Example: `# Require two approvals and passing CI on main
|
Example: `# Require two approvals and passing CI on main
|
||||||
$ tea branch protect main --required-approvals 2 --status-check ci/build
|
$ tea branch protect main --required-approvals 2 --status-check ci/build
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
|
|
||||||
var visibilities = []string{"public", "limited", "private"}
|
var visibilities = []string{"public", "limited", "private"}
|
||||||
|
|
||||||
// visibilityColors color the visibility of organizations and accounts.
|
|
||||||
var visibilityColors = map[string]string{"public": "green", "limited": "yellow", "private": "red"}
|
var visibilityColors = map[string]string{"public": "green", "limited": "yellow", "private": "red"}
|
||||||
|
|
||||||
// timeField shows an API timestamp relative to now on a TTY, and as RFC3339 for scripts.
|
// timeField shows an API timestamp relative to now on a TTY, and as RFC3339 for scripts.
|
||||||
@@ -38,14 +37,6 @@ func timeField(label, raw string, d terminal.Display) terminal.Field {
|
|||||||
return terminal.Field{Label: label, Value: terminal.RelativeTime(now, t)}
|
return terminal.Field{Label: label, Value: terminal.RelativeTime(now, t)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// countOf words a count, such as "1 member" or "2 members".
|
|
||||||
func countOf(n int, singular, plural string) string {
|
|
||||||
if n == 1 {
|
|
||||||
return "1 " + singular
|
|
||||||
}
|
|
||||||
return strconv.Itoa(n) + " " + plural
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *application) organizationCommand() *cobra.Command {
|
func (a *application) organizationCommand() *cobra.Command {
|
||||||
group := &cobra.Command{Use: "org", Short: "Manage organizations", Long: `Work with Gitea organizations: list the ones you belong to, view, create, edit and delete
|
group := &cobra.Command{Use: "org", Short: "Manage organizations", Long: `Work with Gitea organizations: list the ones you belong to, view, create, edit and delete
|
||||||
them, and manage their members.
|
them, and manage their members.
|
||||||
@@ -104,7 +95,7 @@ $ tea org list --all`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *application) organizationViewCommand() *cobra.Command {
|
func (a *application) organizationViewCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "view <org>", Short: "View an organization", Args: argsExact(1),
|
Use: "view <org>", Short: "View an organization", Args: argsExact(1),
|
||||||
Example: `$ tea org view acme
|
Example: `$ tea org view acme
|
||||||
# print the description only
|
# print the description only
|
||||||
@@ -131,7 +122,6 @@ $ tea org view acme --jq .description`,
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return cmd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func organizationView(org services.Organization, size services.OrganizationSize, address string) terminal.View {
|
func organizationView(org services.Organization, size services.OrganizationSize, address string) terminal.View {
|
||||||
@@ -149,7 +139,11 @@ func organizationView(org services.Organization, size services.OrganizationSize,
|
|||||||
singular, plural string
|
singular, plural string
|
||||||
}{{"Members", size.Members, "member", "members"}, {"Teams", size.Teams, "team", "teams"}, {"Repositories", size.Repositories, "repository", "repositories"}} {
|
}{{"Members", size.Members, "member", "members"}, {"Teams", size.Teams, "team", "teams"}, {"Repositories", size.Repositories, "repository", "repositories"}} {
|
||||||
if count.n != nil {
|
if count.n != nil {
|
||||||
counts = append(counts, countOf(*count.n, count.singular, count.plural))
|
noun := count.plural
|
||||||
|
if *count.n == 1 {
|
||||||
|
noun = count.singular
|
||||||
|
}
|
||||||
|
counts = append(counts, strconv.Itoa(*count.n)+" "+noun)
|
||||||
view.Fields = append(view.Fields, terminal.Field{Label: count.label, Value: strconv.Itoa(*count.n), PipedOnly: true})
|
view.Fields = append(view.Fields, terminal.Field{Label: count.label, Value: strconv.Itoa(*count.n), PipedOnly: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +194,6 @@ func organizationFlags(cmd *cobra.Command, create bool) func() services.Organiza
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// organizationName rejects an empty organization argument.
|
|
||||||
func organizationName(raw string) (string, error) {
|
func organizationName(raw string) (string, error) {
|
||||||
if name := strings.TrimSpace(raw); name != "" {
|
if name := strings.TrimSpace(raw); name != "" {
|
||||||
return name, nil
|
return name, nil
|
||||||
@@ -270,11 +263,7 @@ $ tea org edit acme --visibility private`,
|
|||||||
func (a *application) organizationDeleteCommand() *cobra.Command {
|
func (a *application) organizationDeleteCommand() *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "delete <org>", Short: "Delete an organization", Args: argsExact(1), ValidArgsFunction: a.completeOrgs(),
|
Use: "delete <org>", Short: "Delete an organization", Args: argsExact(1), ValidArgsFunction: a.completeOrgs(),
|
||||||
Long: `Delete an organization with its teams. Gitea refuses while the organization owns
|
Long: "Delete an organization with its teams. Gitea refuses while the organization owns repositories.",
|
||||||
repositories: transfer or delete them first.
|
|
||||||
|
|
||||||
The deletion cannot be undone, so a terminal asks you to type the organization's name; --yes
|
|
||||||
skips the question.`,
|
|
||||||
Example: `$ tea org delete acme-old
|
Example: `$ tea org delete acme-old
|
||||||
$ tea org delete acme-old --yes`,
|
$ tea org delete acme-old --yes`,
|
||||||
Annotations: map[string]string{"tea.text": "organization deletion does not return a resource", "tea.confirm": "true"},
|
Annotations: map[string]string{"tea.text": "organization deletion does not return a resource", "tea.confirm": "true"},
|
||||||
@@ -371,7 +360,6 @@ func (a *application) completeOrganizationMembers() cobra.CompletionFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// organizationVisibilityCommand publicizes or conceals an organization membership.
|
|
||||||
func (a *application) organizationVisibilityCommand(public bool) *cobra.Command {
|
func (a *application) organizationVisibilityCommand(public bool) *cobra.Command {
|
||||||
verb, alias, short, state := "conceal", "private", "Hide a membership", "concealed"
|
verb, alias, short, state := "conceal", "private", "Hide a membership", "concealed"
|
||||||
if public {
|
if public {
|
||||||
|
|||||||
@@ -165,11 +165,9 @@ func (a *application) releaseDownloadCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "download [<tag>] [<asset>...]",
|
Use: "download [<tag>] [<asset>...]",
|
||||||
Short: "Download release assets",
|
Short: "Download release assets",
|
||||||
Long: `Download assets of a release, by name or ID, or those matching --pattern; without either, every
|
Long: `Download the assets of a release (default: the latest) by name or ID, those matching --pattern,
|
||||||
asset. --archive downloads the source code archive instead. Without a tag, the latest release is used.
|
or all of them; --archive downloads the source code instead. Existing files are replaced only with
|
||||||
|
--clobber, and --output - writes one asset to standard output.`,
|
||||||
Files are written to the current directory under their names, to --dir, or to --output; an existing
|
|
||||||
file is replaced only with --clobber. --output - writes one asset to standard output.`,
|
|
||||||
Example: `# Download every asset of the latest release
|
Example: `# Download every asset of the latest release
|
||||||
$ tea release download
|
$ tea release download
|
||||||
|
|
||||||
@@ -285,7 +283,6 @@ func selectAssets(release services.Release, names, patterns []string) ([]service
|
|||||||
return selected, nil
|
return selected, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadArchive downloads the source code of the tag as a zip or tar.gz file.
|
|
||||||
func (a *application) downloadArchive(cmd *cobra.Command, service services.Releases, flags downloadFlags, tag, format string) error {
|
func (a *application) downloadArchive(cmd *cobra.Command, service services.Releases, flags downloadFlags, tag, format string) error {
|
||||||
_, repo, _ := strings.Cut(service.Repository, "/")
|
_, repo, _ := strings.Cut(service.Repository, "/")
|
||||||
name := repo + "-" + strings.ReplaceAll(tag, "/", "-") + "." + format
|
name := repo + "-" + strings.ReplaceAll(tag, "/", "-") + "." + format
|
||||||
@@ -311,7 +308,6 @@ func (a *application) downloadArchive(cmd *cobra.Command, service services.Relea
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// countingReader counts the bytes read through it.
|
|
||||||
type countingReader struct {
|
type countingReader struct {
|
||||||
reader io.Reader
|
reader io.Reader
|
||||||
n int64
|
n int64
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ $ tea release view v1.0.0 --web`,
|
|||||||
return command
|
return command
|
||||||
}
|
}
|
||||||
|
|
||||||
// releaseView shows a release with its notes as the body.
|
|
||||||
func (a *application) releaseView(item services.Release, latest int64) terminal.View {
|
func (a *application) releaseView(item services.Release, latest int64) terminal.View {
|
||||||
view := terminal.View{Title: cmp.Or(item.Title, item.Tag), Body: item.Body, Kind: "release", URL: item.URL}
|
view := terminal.View{Title: cmp.Or(item.Title, item.Tag), Body: item.Body, Kind: "release", URL: item.URL}
|
||||||
if item.Title != "" && item.Title != item.Tag {
|
if item.Title != "" && item.Title != item.Tag {
|
||||||
@@ -187,7 +186,6 @@ func (f *releaseFields) register(a *application, cmd *cobra.Command) {
|
|||||||
_ = cmd.RegisterFlagCompletionFunc("target", a.completeBranches())
|
_ = cmd.RegisterFlagCompletionFunc("target", a.completeBranches())
|
||||||
}
|
}
|
||||||
|
|
||||||
// options returns the release fields whose flags were passed.
|
|
||||||
func (f *releaseFields) options(a *application, cmd *cobra.Command) (services.ReleaseOptions, error) {
|
func (f *releaseFields) options(a *application, cmd *cobra.Command) (services.ReleaseOptions, error) {
|
||||||
opts := services.ReleaseOptions{}
|
opts := services.ReleaseOptions{}
|
||||||
changed := cmd.Flags().Changed
|
changed := cmd.Flags().Changed
|
||||||
|
|||||||
@@ -166,14 +166,12 @@ $ tea repo edit --default-merge-style squash --add-topic cli --add-topic go`,
|
|||||||
return services.Classify(err, "branch", strconv.Quote(defaultBranch), t.Repo)
|
return services.Classify(err, "branch", strconv.Quote(defaultBranch), t.Repo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options.Archived != nil && *options.Archived {
|
|
||||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Archive " + t.Repo + "? It becomes read-only."}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Gitea refuses topic changes on an archived repository, so archiving comes last.
|
// Gitea refuses topic changes on an archived repository, so archiving comes last.
|
||||||
repo, archive := t.Repo, options.Archived != nil && *options.Archived
|
repo, archive := t.Repo, options.Archived != nil && *options.Archived
|
||||||
if archive {
|
if archive {
|
||||||
|
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Archive " + t.Repo + "? It becomes read-only."}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
options.Archived = nil
|
options.Archived = nil
|
||||||
}
|
}
|
||||||
if options != (services.RepositoryEdit{}) {
|
if options != (services.RepositoryEdit{}) {
|
||||||
@@ -241,12 +239,9 @@ func (a *application) repoCloneCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "clone <repository> [<directory>] [-- <gitflags>...]",
|
Use: "clone <repository> [<directory>] [-- <gitflags>...]",
|
||||||
Short: "Clone a repository locally",
|
Short: "Clone a repository locally",
|
||||||
Long: `Clone a repository with the configured Git protocol (git_protocol: https or ssh) and tea's
|
Long: `Clone a repository with the configured Git protocol and tea's credentials. Git flags can
|
||||||
credentials. Git flags can follow --.
|
follow --. A fork's parent is added as the "upstream" remote, and tea commands in the clone then
|
||||||
|
target the parent.`,
|
||||||
A fork's parent is added as the "upstream" remote, which its default branch pulls from while pushes
|
|
||||||
stay on the fork; tea commands in the clone then target the parent. A pull mirror's source is added
|
|
||||||
as the "source" remote.`,
|
|
||||||
Example: `# Clone a repository into ./project
|
Example: `# Clone a repository into ./project
|
||||||
$ tea repo clone alice/project
|
$ tea repo clone alice/project
|
||||||
|
|
||||||
@@ -304,12 +299,11 @@ func (a *application) repoForkCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "fork [<repository>] [-- <gitflags>...]",
|
Use: "fork [<repository>] [-- <gitflags>...]",
|
||||||
Short: "Fork a repository",
|
Short: "Fork a repository",
|
||||||
Long: `Fork a repository for your account, or into an organization with --org. When the account or
|
Long: `Fork a repository for your account, or into an organization with --org. An existing fork is
|
||||||
organization already has a fork, tea reports it instead of failing.
|
reported instead of failing.
|
||||||
|
|
||||||
With --clone, the fork is cloned, and its parent is added as the "upstream" remote; Git flags can
|
--clone clones the fork (Git flags can follow --). Inside a clone of the repository, --remote adds
|
||||||
follow --. Inside a clone of the repository, --remote adds the fork as the "origin" remote (or
|
the fork as "origin" and renames the current "origin" to "upstream".`,
|
||||||
--remote-name), renaming the current "origin" to "upstream".`,
|
|
||||||
Example: `# Fork the repository of the current clone and add the fork as origin
|
Example: `# Fork the repository of the current clone and add the fork as origin
|
||||||
$ tea repo fork --remote
|
$ tea repo fork --remote
|
||||||
|
|
||||||
@@ -502,18 +496,13 @@ func (a *application) inferredRepository(t target, verb string, refuseYes bool)
|
|||||||
if t.RepoSource == "--repo" {
|
if t.RepoSource == "--repo" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
source := describeRepoSource(t.RepoSource)
|
source := strings.Replace(t.RepoSource, "remote ", "git remote ", 1)
|
||||||
if refuseYes && a.options.yes {
|
if refuseYes && a.options.yes {
|
||||||
return "", clierr.Wrap(clierr.Usage, fmt.Errorf("--yes requires an explicit repository, not one inferred from %s: tea repo %s %s --yes", source, verb, t.Repo))
|
return "", clierr.Wrap(clierr.Usage, fmt.Errorf("--yes requires an explicit repository, not one inferred from %s: tea repo %s %s --yes", source, verb, t.Repo))
|
||||||
}
|
}
|
||||||
return " (from " + source + ")", nil
|
return " (from " + source + ")", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// describeRepoSource words a repository source for people: git remote upstream, TEA_REPO, ...
|
|
||||||
func describeRepoSource(source string) string {
|
|
||||||
return strings.Replace(source, "remote ", "git remote ", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// repoArchiveCommand builds repo archive, or repo unarchive.
|
// repoArchiveCommand builds repo archive, or repo unarchive.
|
||||||
func (a *application) repoArchiveCommand(archive bool) *cobra.Command {
|
func (a *application) repoArchiveCommand(archive bool) *cobra.Command {
|
||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
@@ -581,7 +570,7 @@ $ tea repo archive alice/old-project --yes`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *application) repoRenameCommand() *cobra.Command {
|
func (a *application) repoRenameCommand() *cobra.Command {
|
||||||
command := &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "rename <new-name>",
|
Use: "rename <new-name>",
|
||||||
Short: "Rename a repository",
|
Short: "Rename a repository",
|
||||||
Long: "Rename a repository; its owner stays the same. Gitea redirects the old name to the new one.",
|
Long: "Rename a repository; its owner stays the same. Gitea redirects the old name to the new one.",
|
||||||
@@ -625,16 +614,13 @@ $ tea repo rename new-name -R alice/old-name`,
|
|||||||
return a.jsonResult(cmd, item)
|
return a.jsonResult(cmd, item)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return command
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *application) repoDeleteCommand() *cobra.Command {
|
func (a *application) repoDeleteCommand() *cobra.Command {
|
||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "delete [<repository>]",
|
Use: "delete [<repository>]",
|
||||||
Short: "Delete a repository",
|
Short: "Delete a repository",
|
||||||
Long: `Delete a repository with its issues, pull requests, releases and wiki. This cannot be undone.
|
Long: "Delete a repository with its issues, pull requests, releases and wiki. This cannot be undone.",
|
||||||
|
|
||||||
Type the repository's name to confirm. With --yes, name the repository explicitly.`,
|
|
||||||
Example: `# Delete a repository after typing its name
|
Example: `# Delete a repository after typing its name
|
||||||
$ tea repo delete alice/old-project
|
$ tea repo delete alice/old-project
|
||||||
|
|
||||||
|
|||||||
@@ -61,10 +61,8 @@ func (a *application) repoSetDefaultCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "set-default [<repository>]",
|
Use: "set-default [<repository>]",
|
||||||
Short: "Set the default repository for this clone",
|
Short: "Set the default repository for this clone",
|
||||||
Long: `Set the repository that tea commands use in the current Git clone, instead of the one found through
|
Long: `Set the repository that tea commands use in the current Git clone instead of the one of its Git
|
||||||
its Git remotes. It is saved as tea.repository in the clone's Git configuration.
|
remotes (saved as tea.repository in the clone's Git configuration).`,
|
||||||
|
|
||||||
Without an argument, the repository that tea selects now is saved.`,
|
|
||||||
Example: `# Make tea commands in this clone use the fork's parent
|
Example: `# Make tea commands in this clone use the fork's parent
|
||||||
$ tea repo set-default alice/project
|
$ tea repo set-default alice/project
|
||||||
|
|
||||||
@@ -280,7 +278,6 @@ $ tea repo view alice/project --web`,
|
|||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
// repositoryView shows a repository with its README as the body.
|
|
||||||
func (a *application) repositoryView(item services.Repository, readme string) terminal.View {
|
func (a *application) repositoryView(item services.Repository, readme string) terminal.View {
|
||||||
badges := []terminal.Cell{{Text: "public", Color: "green"}}
|
badges := []terminal.Cell{{Text: "public", Color: "green"}}
|
||||||
if item.Private {
|
if item.Private {
|
||||||
|
|||||||
@@ -36,11 +36,9 @@ func (a *application) repoCreateCommand() *cobra.Command {
|
|||||||
Short: "Create a repository",
|
Short: "Create a repository",
|
||||||
Long: `Create a repository for your account, or for an organization as ORG/NAME or with --org.
|
Long: `Create a repository for your account, or for an organization as ORG/NAME or with --org.
|
||||||
|
|
||||||
A new repository is empty unless --auto-init adds a first commit with a README and, optionally, a
|
--auto-init adds a first commit with a README, .gitignore and license; --template copies another
|
||||||
.gitignore and a license from the server's templates. --template copies another repository instead.
|
repository. --source adds the new repository as a remote of a local Git repository, and --push
|
||||||
|
pushes its current branch there.`,
|
||||||
--source publishes an existing local Git repository: it adds the new repository as a remote of
|
|
||||||
it (origin unless --remote names another), and --push pushes the current branch there.`,
|
|
||||||
Example: `# Create a private repository with a README and an MIT license
|
Example: `# Create a private repository with a README and an MIT license
|
||||||
$ tea repo create project --private --auto-init --license MIT
|
$ tea repo create project --private --auto-init --license MIT
|
||||||
|
|
||||||
@@ -83,7 +81,7 @@ $ tea repo create project --source . --push`,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prompted, err := a.requireInput(cmd, &opts.Name, "name", "Repository name", func(name string) error { return validateRepositoryName(name) })
|
prompted, err := a.requireInput(cmd, &opts.Name, "name", "Repository name", validateRepositoryName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -130,11 +128,8 @@ $ tea repo create project --source . --push`,
|
|||||||
}
|
}
|
||||||
var item services.Repository
|
var item services.Repository
|
||||||
if template != "" {
|
if template != "" {
|
||||||
templateOpts.Name = opts.Name
|
templateOpts.Name, templateOpts.Owner, templateOpts.Description = opts.Name, org, opts.Description
|
||||||
templateOpts.Owner = org
|
templateOpts.Private, templateOpts.DefaultBranch = opts.Private, opts.DefaultBranch
|
||||||
templateOpts.Description = opts.Description
|
|
||||||
templateOpts.Private = opts.Private
|
|
||||||
templateOpts.DefaultBranch = opts.DefaultBranch
|
|
||||||
item, err = service.Generate(cmd.Context(), target.Repo, templateOpts)
|
item, err = service.Generate(cmd.Context(), target.Repo, templateOpts)
|
||||||
} else {
|
} else {
|
||||||
item, err = service.Create(cmd.Context(), org, opts)
|
item, err = service.Create(cmd.Context(), org, opts)
|
||||||
|
|||||||
@@ -44,12 +44,9 @@ func (a *application) repoMigrateCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "migrate [<clone-url>]",
|
Use: "migrate [<clone-url>]",
|
||||||
Short: "Import a repository from another server",
|
Short: "Import a repository from another server",
|
||||||
Long: `Import a repository into Gitea from a Git URL, or from another forge with --service, which also
|
Long: `Import a repository from a Git URL, or from another forge with --service (which needs an access
|
||||||
copies its issues, labels, milestones, pull requests, releases or wiki on request. --mirror creates
|
token and can also copy issues, pull requests, releases and more). --mirror creates a pull mirror
|
||||||
a pull mirror that Gitea updates from the source instead.
|
instead. The name defaults to the last segment of the URL.`,
|
||||||
|
|
||||||
The repository is named after the last segment of the URL unless --name is given. Imports from a
|
|
||||||
forge with --service need an access token for it.`,
|
|
||||||
Example: `# Import a public Git repository
|
Example: `# Import a public Git repository
|
||||||
$ tea repo migrate https://github.com/go-gitea/tea.git
|
$ tea repo migrate https://github.com/go-gitea/tea.git
|
||||||
|
|
||||||
@@ -81,7 +78,7 @@ $ tea repo migrate https://github.com/acme/tool --service github --issues --pull
|
|||||||
if err := validateMigrationFlags(cmd, opts, passwordFile, tokenFile); err != nil {
|
if err := validateMigrationFlags(cmd, opts, passwordFile, tokenFile); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
validURL := func(raw string) error { return validateMigrationURL(raw) }
|
validURL := validateMigrationURL
|
||||||
if cmd.Flags().Changed("server-path") {
|
if cmd.Flags().Changed("server-path") {
|
||||||
validURL = nil
|
validURL = nil
|
||||||
}
|
}
|
||||||
@@ -95,7 +92,7 @@ $ tea repo migrate https://github.com/acme/tool --service github --issues --pull
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts.Name = cmp.Or(opts.Name, migrationName(opts.CloneURL))
|
opts.Name = cmp.Or(opts.Name, migrationName(opts.CloneURL))
|
||||||
named, err := a.requireInput(cmd, &opts.Name, "name", "Repository name", func(name string) error { return validateRepositoryName(name) })
|
named, err := a.requireInput(cmd, &opts.Name, "name", "Repository name", validateRepositoryName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,14 +21,11 @@ func (a *application) repositorySyncCommand() *cobra.Command {
|
|||||||
command := &cobra.Command{
|
command := &cobra.Command{
|
||||||
Use: "sync [<repository>]",
|
Use: "sync [<repository>]",
|
||||||
Short: "Sync a branch with its remote or its fork's parent",
|
Short: "Sync a branch with its remote or its fork's parent",
|
||||||
Long: `Fast-forward a local branch to the branch of the same name on the repository's Git remote.
|
Long: `Fast-forward a local branch (default: the repository's default branch) to the same branch on
|
||||||
|
the repository's Git remote, without switching branches. Diverged branches are left unchanged.
|
||||||
|
|
||||||
The branch defaults to the repository's default branch. It is created when it is missing, and it is
|
Given a repository without a Git remote here, sync updates it on the server instead: a fork
|
||||||
never checked out: the branch you are on stays checked out. When the branch is checked out, the
|
fast-forwards to its parent, and a pull mirror fetches its source.`,
|
||||||
working tree must be clean. Branches that have diverged from the remote are left unchanged.
|
|
||||||
|
|
||||||
Given a repository that has no remote in the current directory, sync updates it on the server
|
|
||||||
instead: a fork's branch is fast-forwarded to its parent's, and a pull mirror fetches its source.`,
|
|
||||||
Example: `# Fast-forward the default branch from the repository's remote
|
Example: `# Fast-forward the default branch from the repository's remote
|
||||||
$ tea repo sync
|
$ tea repo sync
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ func parseTeam(raw string) (teamRef, error) {
|
|||||||
return teamRef{}, clierr.Wrap(clierr.Usage, fmt.Errorf("invalid team %q: use ORG/TEAM, such as acme/developers, or a team ID", raw))
|
return teamRef{}, clierr.Wrap(clierr.Usage, fmt.Errorf("invalid team %q: use ORG/TEAM, such as acme/developers, or a team ID", raw))
|
||||||
}
|
}
|
||||||
|
|
||||||
// find looks the team up on the instance.
|
|
||||||
func (r teamRef) find(ctx context.Context, service services.Teams) (services.Team, error) {
|
func (r teamRef) find(ctx context.Context, service services.Teams) (services.Team, error) {
|
||||||
if r.org != "" {
|
if r.org != "" {
|
||||||
return service.Find(ctx, r.org, r.name)
|
return service.Find(ctx, r.org, r.name)
|
||||||
@@ -63,7 +62,6 @@ func (a *application) team(cmd *cobra.Command, raw string) (target, services.Tea
|
|||||||
return t, service, team, err
|
return t, service, team, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// teamURL is the page of a team on its instance.
|
|
||||||
func teamURL(t target, team services.Team) string {
|
func teamURL(t target, team services.Team) string {
|
||||||
return webURL(t, "org", team.Organization, "teams", strings.ToLower(team.Name))
|
return webURL(t, "org", team.Organization, "teams", strings.ToLower(team.Name))
|
||||||
}
|
}
|
||||||
@@ -284,7 +282,6 @@ func (f *teamFlags) unitPolicy(cmd *cobra.Command, create bool) (map[string]stri
|
|||||||
return policy, nil
|
return policy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// options returns the supplied team fields.
|
|
||||||
func (f *teamFlags) options(cmd *cobra.Command) services.TeamOptions {
|
func (f *teamFlags) options(cmd *cobra.Command) services.TeamOptions {
|
||||||
opts := services.TeamOptions{}
|
opts := services.TeamOptions{}
|
||||||
for _, field := range []struct {
|
for _, field := range []struct {
|
||||||
@@ -436,10 +433,7 @@ func (a *application) teamDeleteCommand() *cobra.Command {
|
|||||||
var force bool
|
var force bool
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "delete <team>", Short: "Delete a team", Args: argsExact(1), ValidArgsFunction: a.completeTeams(),
|
Use: "delete <team>", Short: "Delete a team", Args: argsExact(1), ValidArgsFunction: a.completeTeams(),
|
||||||
Long: `Delete a team. Its members lose the access the team gave them.
|
Long: "Delete a team. Deleting an organization's owner team needs --force.",
|
||||||
|
|
||||||
Deleting an organization's owner team takes away owner access, so it needs --force and, on a
|
|
||||||
terminal, typing ORG/TEAM.`,
|
|
||||||
Example: `$ tea team delete acme/reviewers
|
Example: `$ tea team delete acme/reviewers
|
||||||
$ tea team delete 7 --yes`,
|
$ tea team delete 7 --yes`,
|
||||||
Annotations: map[string]string{"tea.text": "team deletion does not return a resource", "tea.confirm": "true", "tea.arguments": teamArguments},
|
Annotations: map[string]string{"tea.text": "team deletion does not return a resource", "tea.confirm": "true", "tea.arguments": teamArguments},
|
||||||
@@ -610,7 +604,6 @@ its organization. Repositories are named alone, such as service, or as ORG/NAME.
|
|||||||
return group
|
return group
|
||||||
}
|
}
|
||||||
|
|
||||||
// teamRepoAccessCommand grants or revokes team access to repositories.
|
|
||||||
func (a *application) teamRepoAccessCommand(grant bool) *cobra.Command {
|
func (a *application) teamRepoAccessCommand(grant bool) *cobra.Command {
|
||||||
verb, short, example := "remove", "Revoke team access to repositories", "$ tea team repo remove acme/developers legacy"
|
verb, short, example := "remove", "Revoke team access to repositories", "$ tea team repo remove acme/developers legacy"
|
||||||
annotations := map[string]string{"tea.text": "team access changes do not return a resource", "tea.arguments": teamArguments, "tea.confirm": "true"}
|
annotations := map[string]string{"tea.text": "team access changes do not return a resource", "tea.arguments": teamArguments, "tea.confirm": "true"}
|
||||||
|
|||||||
Reference in new issue
Block a user