From 8aad80107188536ef8398036f94f62cb36169f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=99=93=E4=BC=9F?= Date: Mon, 4 Dec 2023 17:47:38 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E8=BD=AC=E7=A7=BB=EF=BC=88?= =?UTF-8?q?=E6=B7=B7=E5=90=88=E5=91=BD=E4=BB=A4=EF=BC=8C=E5=A4=9A=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=91=BD=E4=BB=A4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 25 +++++++++++++++ constant/common.go | 2 ++ flag/flag.go | 16 ++++++++++ main.go | 1 + mix/mix_transfer.go | 19 ++++++++++++ mix/transfer_all.go | 73 ++++++++++++++++++++++++++++++++++++++++++++ projects/projects.go | 65 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 201 insertions(+) create mode 100644 mix/mix_transfer.go create mode 100644 mix/transfer_all.go diff --git a/README.md b/README.md index 0d4a4dd..e75372d 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ COMMANDS: mix-delete, mix-rm 删除(混合命令,多接口命令) mix-archive 归档(混合命令,多接口命令) mix-export 导出(混合命令,多接口命令) + mix-transfer 转移(混合命令,多接口命令) help, h Shows a list of commands or help for one command GLOBAL OPTIONS: @@ -563,6 +564,30 @@ COPYRIGHT: --help, -h show help ``` +- 转移(混合命令,多接口命令) + + ```shell + $ go run main.go mix-transfer --help + NAME: + gitlab-go mix-transfer - 转移(混合命令,多接口命令) + + USAGE: + gitlab-go mix-transfer command [command options] [arguments...] + + COMMANDS: + all, a 将一个命令空间的项目转移到新的命名空间 + help, h Shows a list of commands or help for one command + + OPTIONS: + --base-url value 实例地址,例如:https://gitlab.xuxiaowei.com.cn/api/v4 (default: "https://gitlab.com/api/v4") [%CI_API_V4_URL%] + --token value your_access_token + --owned 当前用户明确拥有的项目。 (default: false) + --namespace-source value 源命名空间。如:用户名、群组名 + --namespace-target value 源命名空间。如:用户名、群组名 + --skip-project-path value [ --skip-project-path value ] 跳过项目路径 + --help, -h show help + ``` + ### test ```shell diff --git a/constant/common.go b/constant/common.go index 74bd844..00f0502 100644 --- a/constant/common.go +++ b/constant/common.go @@ -25,6 +25,8 @@ const ( IssueIdRange = "issue-id-range" Recursion = "recursion" Owned = "owned" + NamespaceSource = "namespace-source" + NamespaceTarget = "namespace-target" ExportFolder = "export-folder" SkipProjectPath = "skip-project-path" SkipProjectWikiPath = "skip-project-wiki-path" diff --git a/flag/flag.go b/flag/flag.go index 9d6ef51..76d1636 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -192,6 +192,22 @@ func Owned(required bool) cli.Flag { } } +func NamespaceSource(required bool) cli.Flag { + return &cli.StringFlag{ + Name: constant.NamespaceSource, + Usage: "源命名空间。如:用户名、群组名", + Required: required, + } +} + +func NamespaceTargetFlag(required bool) cli.Flag { + return &cli.StringFlag{ + Name: constant.NamespaceTarget, + Usage: "源命名空间。如:用户名、群组名", + Required: required, + } +} + func IssueIdRange(required bool) cli.Flag { return &cli.StringSliceFlag{ Name: constant.IssueIdRange, diff --git a/main.go b/main.go index ec70654..df63a54 100644 --- a/main.go +++ b/main.go @@ -79,6 +79,7 @@ func main() { mix.Delete(), mix.Archive(), mix.Export(), + mix.Transfer(), }, } diff --git a/mix/mix_transfer.go b/mix/mix_transfer.go new file mode 100644 index 0000000..b7f0c64 --- /dev/null +++ b/mix/mix_transfer.go @@ -0,0 +1,19 @@ +package mix + +import ( + "github.com/urfave/cli/v2" + "github.com/xuxiaowei-com-cn/gitlab-go/flag" +) + +// Transfer 转移 +func Transfer() *cli.Command { + return &cli.Command{ + Name: "mix-transfer", + Usage: "转移(混合命令,多接口命令)", + Flags: append(flag.Common(), flag.Owned(false), + flag.NamespaceSource(false), flag.NamespaceTargetFlag(false), flag.SkipProjectPath()), + Subcommands: []*cli.Command{ + TransferAll(), + }, + } +} diff --git a/mix/transfer_all.go b/mix/transfer_all.go new file mode 100644 index 0000000..a45c399 --- /dev/null +++ b/mix/transfer_all.go @@ -0,0 +1,73 @@ +package mix + +import ( + "github.com/urfave/cli/v2" + "github.com/xanzy/go-gitlab" + "github.com/xuxiaowei-com-cn/gitlab-go/constant" + "github.com/xuxiaowei-com-cn/gitlab-go/flag" + "github.com/xuxiaowei-com-cn/gitlab-go/projects" + "log" + "strings" +) + +func TransferAll() *cli.Command { + return &cli.Command{ + Name: "all", + Aliases: []string{"a"}, + Usage: "将一个命令空间的项目转移到新的命名空间", + Flags: append(flag.CommonTokenRequired(), flag.Owned(true), flag.NamespaceSource(true), + flag.NamespaceTargetFlag(true), flag.SkipProjectPath()), + Action: func(context *cli.Context) error { + var baseUrl = context.String(constant.BaseUrl) + var token = context.String(constant.Token) + var owned = context.Bool(constant.Owned) + var namespaceSource = context.String(constant.NamespaceSource) + var namespaceTarget = context.String(constant.NamespaceTarget) + var skipProjectPaths = context.StringSlice(constant.SkipProjectPath) + + for index, skipProjectPath := range skipProjectPaths { + skipProjectPath = strings.TrimPrefix(skipProjectPath, "/") + skipProjectPath = strings.TrimSuffix(skipProjectPath, "/") + skipProjectPaths[index] = skipProjectPath + } + + projectList, err := projects.ListNamespaceProjects(owned, token, baseUrl, 1, 100, namespaceSource, skipProjectPaths) + if err != nil { + return err + } + + for _, project := range projectList { + log.Printf(project.WebURL) + + err = TransferProject(baseUrl, token, project.PathWithNamespace, namespaceTarget) + if err != nil { + return err + } + } + + return nil + }, + } +} + +// TransferProject 将项目转移到新的命名空间 https://docs.gitlab.cn/jh/api/projects.html#%E5%B0%86%E9%A1%B9%E7%9B%AE%E8%BD%AC%E7%A7%BB%E5%88%B0%E6%96%B0%E7%9A%84%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4 +func TransferProject(baseUrl string, token string, id string, namespace string) error { + + gitClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseUrl)) + if err != nil { + return err + } + + opt := &gitlab.TransferProjectOptions{ + Namespace: namespace, + } + + project, response, err := gitClient.Projects.TransferProject(id, opt) + if err != nil { + return err + } + + log.Printf("项目: %s 转移到: %s 结果: %s", id, project.WebURL, response.Status) + + return nil +} diff --git a/projects/projects.go b/projects/projects.go index 902a07a..960091a 100644 --- a/projects/projects.go +++ b/projects/projects.go @@ -5,6 +5,7 @@ import ( "github.com/xanzy/go-gitlab" "github.com/xuxiaowei-com-cn/gitlab-go/flag" "log" + "strings" ) const ( @@ -64,6 +65,70 @@ func ListProjects(owned bool, token string, baseUrl string, page int, perPage in return results, err } +// ListNamespaceProjects 列出命名空间所有项目 +func ListNamespaceProjects(owned bool, token string, baseUrl string, page int, perPage int, namespace string, skipProjectPaths []string) ([]*gitlab.Project, error) { + var results []*gitlab.Project + + gitClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseUrl)) + if err != nil { + return nil, err + } + + opt := &gitlab.ListProjectsOptions{ + ListOptions: gitlab.ListOptions{ + Page: page, + PerPage: perPage, + }, + Owned: &owned, + } + + projects, response, err := gitClient.Projects.ListProjects(opt) + if err != nil { + return nil, err + } + + log.Printf("ListProjects Page %d, PerPage: %d, Response StatusCode: %d\n", page, perPage, response.Response.StatusCode) + + results = Namespace(results, projects, namespace, skipProjectPaths) + + if len(projects) != 0 { + projects, err = ListNamespaceProjects(owned, token, baseUrl, page+1, perPage, namespace, skipProjectPaths) + if err != nil { + return nil, err + } + + results = Namespace(results, projects, namespace, skipProjectPaths) + } + + return results, err +} + +func Namespace(results []*gitlab.Project, projects []*gitlab.Project, namespace string, skipProjectPaths []string) []*gitlab.Project { + if namespace == "" { + results = append(results, projects...) + } else { + for _, project := range projects { + var c bool + for _, skipProjectPath := range skipProjectPaths { + if project.NameWithNamespace == skipProjectPath { + c = true + break + } + } + if c { + break + } + + if strings.HasPrefix(project.PathWithNamespace, namespace+"/") { + // 将 project 添加到 results 中 + results = append(results, project) + } + } + } + + return results +} + func ArchiveProject(token string, baseUrl string, pathWithNamespace string) error { gitClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseUrl)) -- GitLab