mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 08:21:11 +00:00 
			
		
		
		
	urfave/cli v2 will eventually become unmaintained, switch over to v3 which is the latest supported version. Note: the `docs` command would be a lot of work to restore with v3 ([the package is still in alpha](https://github.com/urfave/cli-docs)) An alternative to avoid a breaking change would be to not upgrade from v2 to v3 for that reason alone. Note: these commits were cherry-picked from https://code.forgejo.org/forgefriends/forgefriends Note: it is best reviewed side by side with no display of whitespace changes (there are a lot of those when converting vars to func). - a few functional changes were necessary and are noted in context in the file changes tab - https://cli.urfave.org/migrate-v2-to-v3/ upgrade instructions were followed in the most minimal way possible - upgrade gof3 to v3.10.8 which includes and upgrade from urfave/cli v2 to urfave/cli v3 - upgrade gitlab.com/gitlab-org/api/client-go v0.129.0 because it is an indirect dependency of gof3 and requires a change because of a deprecated field that otherwise triggers a lint error but nothing else otherwise - verified that the [script](https://codeberg.org/forgejo/docs/src/branch/next/scripts/cli-docs.sh) that generates the [CLI documentation](https://codeberg.org/forgejo/docs/src/branch/next/scripts/cli-docs.sh) still works. There are cosmetic differences and the **help** subcommand is no longer advertised (although it is still supported) but the `--help` option is advertised as expected so it is fine. - end-to-end tests [passed](https://code.forgejo.org/forgejo/end-to-end/pulls/667) (they use the Forgejo CLI to some extent) ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [ ] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] I do not want this change to show in the release notes. - [ ] I want the title to show in the release notes with a link to this pull request. - [x] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title. <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Breaking features - [PR](https://codeberg.org/forgejo/forgejo/pulls/8035): <!--number 8035 --><!--line 0 --><!--description VGhlIGBmb3JnZWpvIGRvY3NgIGNvbW1hbmQgaXMgZGVwcmVjYXRlZCBhbmQgQ0xJIGVycm9ycyBhcmUgbm93IGRpc3BsYXllZCBvbiBzdGRlcnIgaW5zdGVhZCBvZiBzdGRvdXQuIFRoZXNlIGJyZWFraW5nIGNoYW5nZXMgaGFwcGVuZWQgYmVjYXVzZSB0aGUgcGFja2FnZSB1c2VkIHRvIHBhcnNlIHRoZSBjb21tYW5kIGxpbmUgYXJndW1lbnRzIHdhcyBbdXBncmFkZWQgZnJvbSB2MiB0byB2M10oaHR0cHM6Ly9jbGkudXJmYXZlLm9yZy9taWdyYXRlLXYyLXRvLXYzLykuIEEgW3NlcGFyYXRlIHByb2plY3Qgd2FzIGluaXRpYXRlZF0oaHR0cHM6Ly9naXRodWIuY29tL3VyZmF2ZS9jbGktZG9jcykgdG8gcmUtaW1wbGVtZW50IHRoZSBgZG9jc2AgY29tbWFuZCwgYnV0IGl0IGlzIG5vdCB5ZXQgcHJvZHVjdGlvbiByZWFkeS4=-->The `forgejo docs` command is deprecated and CLI errors are now displayed on stderr instead of stdout. These breaking changes happened because the package used to parse the command line arguments was [upgraded from v2 to v3](https://cli.urfave.org/migrate-v2-to-v3/). A [separate project was initiated](https://github.com/urfave/cli-docs) to re-implement the `docs` command, but it is not yet production ready.<!--description--> <!--end release-notes-assistant--> Co-authored-by: limiting-factor <limiting-factor@posteo.com> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8035 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
		
			
				
	
	
		
			194 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2020 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package cmd
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"forgejo.org/modules/git"
 | 
						|
	"forgejo.org/modules/log"
 | 
						|
	base "forgejo.org/modules/migration"
 | 
						|
	"forgejo.org/modules/setting"
 | 
						|
	"forgejo.org/modules/structs"
 | 
						|
	"forgejo.org/modules/util"
 | 
						|
	"forgejo.org/services/convert"
 | 
						|
	"forgejo.org/services/migrations"
 | 
						|
 | 
						|
	"github.com/urfave/cli/v3"
 | 
						|
)
 | 
						|
 | 
						|
// CmdDumpRepository represents the available dump repository sub-command.
 | 
						|
func cmdDumpRepository() *cli.Command {
 | 
						|
	return &cli.Command{
 | 
						|
		Name:        "dump-repo",
 | 
						|
		Usage:       "Dump the repository from git/github/gitea/gitlab",
 | 
						|
		Description: "This is a command for dumping the repository data.",
 | 
						|
		Action:      runDumpRepository,
 | 
						|
		Flags: []cli.Flag{
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "git_service",
 | 
						|
				Value: "",
 | 
						|
				Usage: "Git service, git, github, gitea, gitlab. If clone_addr could be recognized, this could be ignored.",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:    "repo_dir",
 | 
						|
				Aliases: []string{"r"},
 | 
						|
				Value:   "./data",
 | 
						|
				Usage:   "Repository dir path to store the data",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "clone_addr",
 | 
						|
				Value: "",
 | 
						|
				Usage: "The URL will be clone, currently could be a git/github/gitea/gitlab http/https URL",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "auth_username",
 | 
						|
				Value: "",
 | 
						|
				Usage: "The username to visit the clone_addr",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "auth_password",
 | 
						|
				Value: "",
 | 
						|
				Usage: "The password to visit the clone_addr",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "auth_token",
 | 
						|
				Value: "",
 | 
						|
				Usage: "The personal token to visit the clone_addr",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "owner_name",
 | 
						|
				Value: "",
 | 
						|
				Usage: "The data will be stored on a directory with owner name if not empty",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "repo_name",
 | 
						|
				Value: "",
 | 
						|
				Usage: "The data will be stored on a directory with repository name if not empty",
 | 
						|
			},
 | 
						|
			&cli.StringFlag{
 | 
						|
				Name:  "units",
 | 
						|
				Value: "",
 | 
						|
				Usage: `Which items will be migrated, one or more units should be separated as comma.
 | 
						|
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func runDumpRepository(stdCtx context.Context, ctx *cli.Command) error {
 | 
						|
	stdCtx, cancel := installSignals(stdCtx)
 | 
						|
	defer cancel()
 | 
						|
 | 
						|
	if err := initDB(stdCtx); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// migrations.GiteaLocalUploader depends on git module
 | 
						|
	if err := git.InitSimple(context.Background()); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	log.Info("AppPath: %s", setting.AppPath)
 | 
						|
	log.Info("AppWorkPath: %s", setting.AppWorkPath)
 | 
						|
	log.Info("Custom path: %s", setting.CustomPath)
 | 
						|
	log.Info("Log path: %s", setting.Log.RootPath)
 | 
						|
	log.Info("Configuration file: %s", setting.CustomConf)
 | 
						|
 | 
						|
	var (
 | 
						|
		serviceType structs.GitServiceType
 | 
						|
		cloneAddr   = ctx.String("clone_addr")
 | 
						|
		serviceStr  = ctx.String("git_service")
 | 
						|
	)
 | 
						|
 | 
						|
	if strings.HasPrefix(strings.ToLower(cloneAddr), "https://github.com/") {
 | 
						|
		serviceStr = "github"
 | 
						|
	} else if strings.HasPrefix(strings.ToLower(cloneAddr), "https://gitlab.com/") {
 | 
						|
		serviceStr = "gitlab"
 | 
						|
	} else if strings.HasPrefix(strings.ToLower(cloneAddr), "https://gitea.com/") {
 | 
						|
		serviceStr = "gitea"
 | 
						|
	}
 | 
						|
	if serviceStr == "" {
 | 
						|
		return errors.New("git_service missed or clone_addr cannot be recognized")
 | 
						|
	}
 | 
						|
	serviceType = convert.ToGitServiceType(serviceStr)
 | 
						|
 | 
						|
	opts := base.MigrateOptions{
 | 
						|
		GitServiceType: serviceType,
 | 
						|
		CloneAddr:      cloneAddr,
 | 
						|
		AuthUsername:   ctx.String("auth_username"),
 | 
						|
		AuthPassword:   ctx.String("auth_password"),
 | 
						|
		AuthToken:      ctx.String("auth_token"),
 | 
						|
		RepoName:       ctx.String("repo_name"),
 | 
						|
	}
 | 
						|
 | 
						|
	if len(ctx.String("units")) == 0 {
 | 
						|
		opts.Wiki = true
 | 
						|
		opts.Issues = true
 | 
						|
		opts.Milestones = true
 | 
						|
		opts.Labels = true
 | 
						|
		opts.Releases = true
 | 
						|
		opts.Comments = true
 | 
						|
		opts.PullRequests = true
 | 
						|
		opts.ReleaseAssets = true
 | 
						|
	} else {
 | 
						|
		units := strings.Split(ctx.String("units"), ",")
 | 
						|
		for _, unit := range units {
 | 
						|
			switch strings.ToLower(strings.TrimSpace(unit)) {
 | 
						|
			case "":
 | 
						|
				continue
 | 
						|
			case "wiki":
 | 
						|
				opts.Wiki = true
 | 
						|
			case "issues":
 | 
						|
				opts.Issues = true
 | 
						|
			case "milestones":
 | 
						|
				opts.Milestones = true
 | 
						|
			case "labels":
 | 
						|
				opts.Labels = true
 | 
						|
			case "releases":
 | 
						|
				opts.Releases = true
 | 
						|
			case "release_assets":
 | 
						|
				opts.ReleaseAssets = true
 | 
						|
			case "comments":
 | 
						|
				opts.Comments = true
 | 
						|
			case "pull_requests":
 | 
						|
				opts.PullRequests = true
 | 
						|
			default:
 | 
						|
				return errors.New("invalid unit: " + unit)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// the repo_dir will be removed if error occurs in DumpRepository
 | 
						|
	// make sure the directory doesn't exist or is empty, prevent from deleting user files
 | 
						|
	repoDir := ctx.String("repo_dir")
 | 
						|
	if exists, err := util.IsExist(repoDir); err != nil {
 | 
						|
		return fmt.Errorf("unable to stat repo_dir %q: %w", repoDir, err)
 | 
						|
	} else if exists {
 | 
						|
		if isDir, _ := util.IsDir(repoDir); !isDir {
 | 
						|
			return fmt.Errorf("repo_dir %q already exists but it's not a directory", repoDir)
 | 
						|
		}
 | 
						|
		if dir, _ := os.ReadDir(repoDir); len(dir) > 0 {
 | 
						|
			return fmt.Errorf("repo_dir %q is not empty", repoDir)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if err := migrations.DumpRepository(
 | 
						|
		context.Background(),
 | 
						|
		repoDir,
 | 
						|
		ctx.String("owner_name"),
 | 
						|
		opts,
 | 
						|
	); err != nil {
 | 
						|
		log.Fatal("Failed to dump repository: %v", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	log.Trace("Dump finished!!!")
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 |