diff --git a/cnb-builder-shim/cmd/dev-entrypoint/init.go b/cnb-builder-shim/cmd/dev-entrypoint/init.go index e67613d7e..bd8c3a361 100644 --- a/cnb-builder-shim/cmd/dev-entrypoint/init.go +++ b/cnb-builder-shim/cmd/dev-entrypoint/init.go @@ -20,6 +20,7 @@ package main import ( "fmt" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/vcs" "os" "path/filepath" "strings" @@ -29,7 +30,6 @@ import ( "github.com/pkg/errors" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/config" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/filediffer" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/fetcher/http" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/utils" ) @@ -171,8 +171,8 @@ func initializeSourceCode() error { } // 初始化文件对比器 - if err = filediffer.New().Prepare(workspace); err != nil { - return errors.Wrap(err, "file differ preparing") + if err = vcs.New().Prepare(workspace); err != nil { + return errors.Wrap(err, "version controller preparing") } return nil } @@ -183,7 +183,7 @@ func ensureWorkspace(workspace string) (err error) { if _, err = os.Stat(workspace); os.IsNotExist(err) { // 文件夹不存在,创建文件夹 logger.Info("create workspace directory") - if err := os.MkdirAll(workspace, 0750); err != nil { + if err = os.MkdirAll(workspace, 0750); err != nil { return errors.Wrap(err, "create workspace directory") } return nil diff --git a/cnb-builder-shim/cmd/dev-entrypoint/main.go b/cnb-builder-shim/cmd/dev-entrypoint/main.go index 81e575022..208f48e9c 100644 --- a/cnb-builder-shim/cmd/dev-entrypoint/main.go +++ b/cnb-builder-shim/cmd/dev-entrypoint/main.go @@ -19,11 +19,11 @@ package main import ( + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/webserver" "os" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/config" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/webserver" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/logging" ) diff --git a/cnb-builder-shim/internal/devsandbox/filediffer/filediffer_suite_test.go b/cnb-builder-shim/internal/devsandbox/filediffer/filediffer_suite_test.go deleted file mode 100644 index 206e8ca5c..000000000 --- a/cnb-builder-shim/internal/devsandbox/filediffer/filediffer_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package filediffer_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestFileDiffer(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "File Differ Suite") -} diff --git a/cnb-builder-shim/internal/devsandbox/vcs/types.go b/cnb-builder-shim/internal/devsandbox/vcs/types.go new file mode 100644 index 000000000..b4b0127c3 --- /dev/null +++ b/cnb-builder-shim/internal/devsandbox/vcs/types.go @@ -0,0 +1,94 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +// Package vcs 版本控制系统(VersionControlSystem) +package vcs + +import ( + "slices" + "strings" +) + +// 强制忽略的文件路径前缀 +var forceIgnoreFilePathPrefixes = []string{"v3logs"} + +// FileAction 文件操作类型 +type FileAction string + +const ( + // FileActionAdded 文件增加 + FileActionAdded FileAction = "added" + // FileActionModified 文件变更 + FileActionModified FileAction = "modified" + // FileActionDeleted 文件删除 + FileActionDeleted FileAction = "deleted" +) + +// File 文件详情 +type File struct { + Action FileAction `json:"action"` + Path string `json:"path"` + Content string `json:"content"` +} + +// Files 文件列表 +type Files []File + +// DirTree 目录树 +type DirTree struct { + Name string `json:"name"` + Dirs []*DirTree `json:"dirs"` + Files Files `json:"files"` +} + +// AsTree 转换成目录树形式 +func (files Files) AsTree() DirTree { + // 按照文件路径排序 + slices.SortFunc(files, func(a, b File) int { + return strings.Compare(a.Path, b.Path) + }) + + root := DirTree{Name: "/"} + var cur *DirTree + for _, f := range files { + parts := strings.Split(f.Path, "/") + cur = &root + // 循环创建目录树 + for _, part := range parts[:len(parts)-1] { + if part == "" { + continue + } + exists := false + for _, dir := range cur.Dirs { + if dir.Name == part { + cur = dir + exists = true + break + } + } + if !exists { + cur.Dirs = append(cur.Dirs, &DirTree{Name: part}) + cur = cur.Dirs[len(cur.Dirs)-1] + } + } + // 目录树格式下,路径即为文件名 + f.Path = parts[len(parts)-1] + cur.Files = append(cur.Files, f) + } + return root +} diff --git a/cnb-builder-shim/internal/devsandbox/vcs/types_test.go b/cnb-builder-shim/internal/devsandbox/vcs/types_test.go new file mode 100644 index 000000000..2701a1d8f --- /dev/null +++ b/cnb-builder-shim/internal/devsandbox/vcs/types_test.go @@ -0,0 +1,83 @@ +/* + * TencentBlueKing is pleased to support the open source community by making + * 蓝鲸智云 - PaaS 平台 (BlueKing - PaaS System) available. + * Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the MIT License (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://opensource.org/licenses/MIT + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * + * We undertake not to change the open source license (MIT license) applicable + * to the current version of the project delivered to anyone in the future. + */ + +package vcs + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("Test Types", func() { + + Context("Test Files", func() { + It("AsTree", func() { + files := Files{ + {Action: FileActionAdded, Path: "README.md"}, + {Action: FileActionAdded, Path: "webfe/static/example.css"}, + {Action: FileActionAdded, Path: "webfe/static/example.js"}, + {Action: FileActionDeleted, Path: "api/main.py"}, + {Action: FileActionDeleted, Path: "webfe/templates/example.html"}, + {Action: FileActionModified, Path: "backend/main.go"}, + {Action: FileActionModified, Path: "backend/types.go"}, + {Action: FileActionModified, Path: "docs/example.txt"}, + } + + excepted := DirTree{ + Name: "/", + Dirs: []*DirTree{ + { + Name: "api", Files: Files{ + {Action: FileActionDeleted, Path: "main.py"}, + }, + }, + { + Name: "backend", Files: Files{ + {Action: FileActionModified, Path: "main.go"}, + {Action: FileActionModified, Path: "types.go"}, + }, + }, + { + Name: "docs", Files: Files{ + {Action: FileActionModified, Path: "example.txt"}, + }, + }, + { + Name: "webfe", Dirs: []*DirTree{ + { + Name: "static", Files: Files{ + {Action: FileActionAdded, Path: "example.css"}, + {Action: FileActionAdded, Path: "example.js"}, + }, + }, + { + Name: "templates", Files: Files{ + {Action: FileActionDeleted, Path: "example.html"}, + }, + }, + }, + }, + }, + Files: Files{ + {Action: FileActionAdded, Path: "README.md"}, + }, + } + Expect(files.AsTree()).To(Equal(excepted)) + }) + }) +}) diff --git a/cnb-builder-shim/internal/devsandbox/filediffer/filediffer.go b/cnb-builder-shim/internal/devsandbox/vcs/vcs.go similarity index 53% rename from cnb-builder-shim/internal/devsandbox/filediffer/filediffer.go rename to cnb-builder-shim/internal/devsandbox/vcs/vcs.go index 3ff7b333d..416284ff1 100644 --- a/cnb-builder-shim/internal/devsandbox/filediffer/filediffer.go +++ b/cnb-builder-shim/internal/devsandbox/vcs/vcs.go @@ -15,7 +15,7 @@ * We undertake not to change the open source license (MIT license) applicable * to the current version of the project delivered to anyone in the future. */ -package filediffer +package vcs import ( "bytes" @@ -24,30 +24,31 @@ import ( "os/exec" "path" "strings" + "unicode" "github.com/pkg/errors" ) -// FileDiffer 文件变更对比器 -type FileDiffer struct { +// VersionController 版本控制器(基于 Git) +type VersionController struct { srcPath string withContent bool } // New ... -func New(opts ...Option) *FileDiffer { - differ := &FileDiffer{} +func New(opts ...Option) *VersionController { + v := &VersionController{} for _, opt := range opts { - opt(differ) + opt(v) } - return differ + return v } // Prepare 准备步骤 -func (d *FileDiffer) Prepare(srcPath string) error { - d.srcPath = srcPath +func (v *VersionController) Prepare(srcPath string) error { + v.srcPath = srcPath - _, err := os.Stat(path.Join(d.srcPath, ".git")) + _, err := os.Stat(path.Join(v.srcPath, ".git")) // 如果对应目录下存在 .git 目录,跳过 if err == nil { return nil @@ -63,7 +64,7 @@ func (d *FileDiffer) Prepare(srcPath string) error { {"commit", "-m", "init"}, } for _, cmd := range commands { - if _, err = d.runGitCommand(cmd...); err != nil { + if _, err = v.runGitCommand(cmd...); err != nil { return err } } @@ -75,57 +76,48 @@ func (d *FileDiffer) Prepare(srcPath string) error { } // Diff 对比输出文件变更信息 -func (d *FileDiffer) Diff() ([]File, error) { - if _, err := d.runGitCommand("add", "."); err != nil { +func (v *VersionController) Diff() (Files, error) { + // 将所有文件添加到暂存区 + if _, err := v.runGitCommand("add", "."); err != nil { return nil, err } - output, err := d.runGitCommand("diff", "--cached", "--name-status") + // 设置不要转义特殊字符 + if _, err := v.runGitCommand("config", "core.quotepath", "false"); err != nil { + return nil, err + } + // 执行 diff 命令输出变更文件目录 + output, err := v.runGitCommand("diff", "--cached", "--name-status", "--no-renames") if err != nil { return nil, err } lines := strings.Split(output, "\n") - files := []File{} + files := Files{} for _, line := range lines { - if line == "" { + action, filePath, pErr := v.parseDiffLine(line) + if pErr != nil { continue } - fields := strings.Fields(line) - if len(fields) != 2 { - return nil, errors.Errorf("invalid line: %s", line) - } - var action FileAction - switch fields[0] { - case "A": - action = FileActionAdded - case "M": - action = FileActionModified - case "D": - action = FileActionDeleted - default: - return nil, errors.Errorf("unknown action: %s", fields[0]) - } // 强制忽略部分变更文件 - if d.mustIgnoreFile(fields[1]) { + if v.shouldIgnoreFile(filePath) { continue } - var content string // 如果是删除操作,不加载文件 - if d.withContent && action != FileActionDeleted { - if content, err = d.loadFileContent(fields[1]); err != nil { + if v.withContent && action != FileActionDeleted { + if content, err = v.loadFileContent(filePath); err != nil { return nil, err } } - files = append(files, File{Action: action, Path: fields[1], Content: content}) + files = append(files, File{Action: action, Path: filePath, Content: content}) } return files, nil } // 执行 Git 命令 -func (d *FileDiffer) runGitCommand(args ...string) (string, error) { +func (v *VersionController) runGitCommand(args ...string) (string, error) { cmd := exec.Command("git", args...) - cmd.Dir = d.srcPath + cmd.Dir = v.srcPath var out bytes.Buffer cmd.Stdout = &out @@ -138,8 +130,8 @@ func (d *FileDiffer) runGitCommand(args ...string) (string, error) { } // 加载指定文件内容 -func (d *FileDiffer) loadFileContent(filepath string) (string, error) { - file, err := os.Open(path.Join(d.srcPath, filepath)) +func (v *VersionController) loadFileContent(filepath string) (string, error) { + file, err := os.Open(path.Join(v.srcPath, filepath)) if err != nil { return "", err } @@ -152,8 +144,32 @@ func (d *FileDiffer) loadFileContent(filepath string) (string, error) { return string(content), nil } +// 解析 git diff 输出的文件变更信息 +func (v *VersionController) parseDiffLine(line string) (FileAction, string, error) { + // diff 输出格式形如: + // A backend/example.go + // M webfe/example.js + // D api/example.py + index := strings.IndexFunc(line, unicode.IsSpace) + if index == -1 { + return "", "", errors.Errorf("invalid diff line: `%s`", line) + } + + rawAction, filepath := line[:index], strings.TrimSpace(line[index+1:]) + switch rawAction { + case "A": + return FileActionAdded, filepath, nil + case "M": + return FileActionModified, filepath, nil + case "D": + return FileActionDeleted, filepath, nil + default: + return "", "", errors.Errorf("unknown action: %s", rawAction) + } +} + // 判断变更的文件是否需要被忽略 -func (d *FileDiffer) mustIgnoreFile(filepath string) bool { +func (v *VersionController) shouldIgnoreFile(filepath string) bool { for _, prefix := range forceIgnoreFilePathPrefixes { if strings.HasPrefix(filepath, prefix) { return true @@ -162,12 +178,12 @@ func (d *FileDiffer) mustIgnoreFile(filepath string) bool { return false } -// Option Differ 选项 -type Option func(*FileDiffer) +// Option VersionController 选项 +type Option func(*VersionController) -// WithContent Diff 时是否加载文件内容 +// WithContent Diff 时加载文件内容 func WithContent() Option { - return func(d *FileDiffer) { - d.withContent = true + return func(v *VersionController) { + v.withContent = true } } diff --git a/cnb-builder-shim/internal/devsandbox/filediffer/types.go b/cnb-builder-shim/internal/devsandbox/vcs/vcs_suite_test.go similarity index 62% rename from cnb-builder-shim/internal/devsandbox/filediffer/types.go rename to cnb-builder-shim/internal/devsandbox/vcs/vcs_suite_test.go index 66090d5f2..a6b45a5a9 100644 --- a/cnb-builder-shim/internal/devsandbox/filediffer/types.go +++ b/cnb-builder-shim/internal/devsandbox/vcs/vcs_suite_test.go @@ -16,26 +16,16 @@ * to the current version of the project delivered to anyone in the future. */ -package filediffer +package vcs_test -// 强制忽略的文件路径前缀 -var forceIgnoreFilePathPrefixes = []string{"v3logs"} +import ( + "testing" -// FileAction 文件操作类型 -type FileAction string - -const ( - // FileActionAdded 文件增加 - FileActionAdded FileAction = "added" - // FileActionModified 文件变更 - FileActionModified FileAction = "modified" - // FileActionDeleted 文件删除 - FileActionDeleted FileAction = "deleted" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" ) -// File 文件详情 -type File struct { - Action FileAction `json:"action"` - Path string `json:"path"` - Content string `json:"content"` +func TestVCS(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "VCS Suite") } diff --git a/cnb-builder-shim/internal/devsandbox/filediffer/filediffer_test.go b/cnb-builder-shim/internal/devsandbox/vcs/vcs_test.go similarity index 78% rename from cnb-builder-shim/internal/devsandbox/filediffer/filediffer_test.go rename to cnb-builder-shim/internal/devsandbox/vcs/vcs_test.go index 78d78a63e..b2187fd74 100644 --- a/cnb-builder-shim/internal/devsandbox/filediffer/filediffer_test.go +++ b/cnb-builder-shim/internal/devsandbox/vcs/vcs_test.go @@ -16,7 +16,7 @@ * to the current version of the project delivered to anyone in the future. */ -package filediffer +package vcs import ( "os" @@ -27,7 +27,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("Test Differ", func() { +var _ = Describe("Test VersionController", func() { var tmpDir string var initFile = func(dir, filename, content string) error { @@ -66,7 +66,7 @@ var _ = Describe("Test Differ", func() { // 初始化临时目录 & 文件 BeforeEach(func() { - tmpDir, _ = os.MkdirTemp("", "file-differ") + tmpDir, _ = os.MkdirTemp("", "vcs") for _, filename := range []string{"example.txt", "example.py", "example.go"} { Expect(initFile(tmpDir, filename, path.Ext(filename))).To(BeNil()) } @@ -76,7 +76,7 @@ var _ = Describe("Test Differ", func() { Expect(os.RemoveAll(tmpDir)).To(BeNil()) }) - Context("Test FileDiffer", func() { + Context("Test VersionController", func() { It("with .git", func() { Expect(runGitCommand(tmpDir, "init")).To(BeNil()) Expect(runGitCommand(tmpDir, "add", ".")).To(BeNil()) @@ -84,36 +84,36 @@ var _ = Describe("Test Differ", func() { Expect(runGitCommand(tmpDir, "config", "user.email", "bkpaas@example.com")).To(BeNil()) Expect(runGitCommand(tmpDir, "commit", "-m", "init")).To(BeNil()) - differ := New(WithContent()) - Expect(differ.Prepare(tmpDir)).To(BeNil()) + verCtrl := New(WithContent()) + Expect(verCtrl.Prepare(tmpDir)).To(BeNil()) - files, err := differ.Diff() + files, err := verCtrl.Diff() Expect(err).To(BeNil()) Expect(files).To(HaveLen(0)) _ = initFile(tmpDir, "example.html", ".html") _ = initFile(tmpDir, "example.js", ".js") - files, err = differ.Diff() + files, err = verCtrl.Diff() Expect(err).To(BeNil()) - Expect(files).To(Equal([]File{ + Expect(files).To(Equal(Files{ {Action: FileActionAdded, Path: "example.html", Content: ".html"}, {Action: FileActionAdded, Path: "example.js", Content: ".js"}, })) _ = os.Remove(path.Join(tmpDir, "example.html")) _ = os.Remove(path.Join(tmpDir, "example.py")) - files, err = differ.Diff() + files, err = verCtrl.Diff() Expect(err).To(BeNil()) - Expect(files).To(Equal([]File{ + Expect(files).To(Equal(Files{ {Action: FileActionAdded, Path: "example.js", Content: ".js"}, {Action: FileActionDeleted, Path: "example.py", Content: ""}, })) _ = editFile(tmpDir, "example.go", "gogo") - files, err = differ.Diff() + files, err = verCtrl.Diff() Expect(err).To(BeNil()) - Expect(files).To(Equal([]File{ + Expect(files).To(Equal(Files{ {Action: FileActionModified, Path: "example.go", Content: "gogo"}, {Action: FileActionAdded, Path: "example.js", Content: ".js"}, {Action: FileActionDeleted, Path: "example.py", Content: ""}, @@ -121,10 +121,10 @@ var _ = Describe("Test Differ", func() { }) It("without .git", func() { - differ := New(WithContent()) - Expect(differ.Prepare(tmpDir)).To(BeNil()) + verCtrl := New(WithContent()) + Expect(verCtrl.Prepare(tmpDir)).To(BeNil()) - files, err := differ.Diff() + files, err := verCtrl.Diff() Expect(err).To(BeNil()) Expect(files).To(HaveLen(0)) @@ -137,10 +137,10 @@ var _ = Describe("Test Differ", func() { _ = editFile(path.Join(tmpDir, "webfe/static"), "example.js", "js-js") _ = editFile(tmpDir, "example.txt", "txt no.1") - files, err = differ.Diff() + files, err = verCtrl.Diff() Expect(err).To(BeNil()) Expect(files).To(HaveLen(5)) - Expect(files).To(Equal([]File{ + Expect(files).To(Equal(Files{ {Action: FileActionModified, Path: "example.go", Content: "gogo"}, {Action: FileActionDeleted, Path: "example.py", Content: ""}, {Action: FileActionModified, Path: "example.txt", Content: "txt no.1"}, @@ -150,8 +150,8 @@ var _ = Describe("Test Differ", func() { }) It("with ignore", func() { - differ := New(WithContent()) - Expect(differ.Prepare(tmpDir)).To(BeNil()) + verCtrl := New(WithContent()) + Expect(verCtrl.Prepare(tmpDir)).To(BeNil()) _ = initFile(path.Join(tmpDir, "webfe/templates"), "example.html", ".html") _ = initFile(path.Join(tmpDir, "v3logs"), "celery.log", "celery is running...") @@ -159,9 +159,9 @@ var _ = Describe("Test Differ", func() { _ = editFile(tmpDir, "example.txt", "txt no.1") _ = os.Remove(path.Join(tmpDir, "example.go")) - files, err := differ.Diff() + files, err := verCtrl.Diff() Expect(err).To(BeNil()) - Expect(files).To(Equal([]File{ + Expect(files).To(Equal(Files{ {Action: FileActionDeleted, Path: "example.go", Content: ""}, {Action: FileActionModified, Path: "example.txt", Content: "txt no.1"}, {Action: FileActionAdded, Path: "webfe/templates/example.html", Content: ".html"}, @@ -169,21 +169,38 @@ var _ = Describe("Test Differ", func() { }) It("without content", func() { - differ := New() - Expect(differ.Prepare(tmpDir)).To(BeNil()) + verCtrl := New() + Expect(verCtrl.Prepare(tmpDir)).To(BeNil()) _ = initFile(path.Join(tmpDir, "webfe/static"), "example.css", "css") _ = initFile(path.Join(tmpDir, "v3logs"), "celery.log", "celery is running...") _ = editFile(tmpDir, "example.py", "python") _ = os.Remove(path.Join(tmpDir, "example.go")) - files, err := differ.Diff() + files, err := verCtrl.Diff() Expect(err).To(BeNil()) - Expect(files).To(Equal([]File{ + Expect(files).To(Equal(Files{ {Action: FileActionDeleted, Path: "example.go", Content: ""}, {Action: FileActionModified, Path: "example.py", Content: ""}, {Action: FileActionAdded, Path: "webfe/static/example.css", Content: ""}, })) }) + + It("with special chars", func() { + verCtrl := New(WithContent()) + Expect(verCtrl.Prepare(tmpDir)).To(BeNil()) + + _ = initFile(tmpDir, "example space.css", "css 代码") + _ = initFile(tmpDir, "example——中文.js", "js 代码") + _ = initFile(tmpDir, "example.tab.html", "html 代码") + + files, err := verCtrl.Diff() + Expect(err).To(BeNil()) + Expect(files).To(Equal(Files{ + {Action: FileActionAdded, Path: "example space.css", Content: "css 代码"}, + {Action: FileActionAdded, Path: "example.tab.html", Content: "html 代码"}, + {Action: FileActionAdded, Path: "example——中文.js", Content: "js 代码"}, + })) + }) }) }) diff --git a/cnb-builder-shim/internal/devsandbox/webserver/server.go b/cnb-builder-shim/internal/devsandbox/webserver/server.go index 39f43a746..8e2dd7b79 100644 --- a/cnb-builder-shim/internal/devsandbox/webserver/server.go +++ b/cnb-builder-shim/internal/devsandbox/webserver/server.go @@ -20,6 +20,8 @@ package webserver import ( "fmt" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox" + "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/vcs" "net/http" "os" "path" @@ -33,9 +35,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-logr/logr" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/config" - "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/filediffer" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/internal/devsandbox/webserver/service" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/appdesc" "github.com/TencentBlueking/bkpaas/cnb-builder-shim/pkg/utils" @@ -297,21 +297,21 @@ func DiffsHandler() gin.HandlerFunc { } // 初始化 - opts := []filediffer.Option{} + opts := []vcs.Option{} if c.Query("content") == "true" { - opts = append(opts, filediffer.WithContent()) + opts = append(opts, vcs.WithContent()) } - differ := filediffer.New(opts...) + verCtrl := vcs.New(opts...) - if err := differ.Prepare(config.G.SourceCode.Workspace); err != nil { + if err := verCtrl.Prepare(config.G.SourceCode.Workspace); err != nil { c.JSON( http.StatusInternalServerError, - gin.H{"message": fmt.Sprintf("file differ prepare failed: %s", err)}, + gin.H{"message": fmt.Sprintf("vcs prepare failed: %s", err)}, ) return } // 获取文件变更信息 - files, err := differ.Diff() + files, err := verCtrl.Diff() if err != nil { c.JSON( http.StatusInternalServerError, @@ -319,7 +319,13 @@ func DiffsHandler() gin.HandlerFunc { ) return } - c.JSON(http.StatusOK, gin.H{"data": files}) + // 如果指定 tree 为 true,则返回目录树格式 + if c.Query("tree") == "true" { + c.JSON(http.StatusOK, gin.H{"total": len(files), "tree": files.AsTree()}) + return + } + // 默认返回变更文件列表 + c.JSON(http.StatusOK, gin.H{"total": len(files), "files": files}) } }