Skip to content

Commit 2b7f418

Browse files
committed
Migrate ziputil from v1 to v2
Swap go-utils v1 ziputil (which shelled out to /usr/bin/zip) for the pure-Go go-utils/v2 ziputil ZipManager. A ZipManager is constructed in main and passed into collectFilesToDeploy and the pipeline-intermediate collector. Bumping go-utils/v2 also re-vendors env, fileutil and pathutil. Add integration tests for the collectFilesToDeploy compress path that run against a real ZipManager, covering symlink storage and archive contents.
1 parent 76b41c1 commit 2b7f418

14 files changed

Lines changed: 1007 additions & 130 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Integration tests that zip real files on disk: symlink and permission handling cannot be
2+
// verified against a mocked filesystem.
3+
package main
4+
5+
import (
6+
"archive/zip"
7+
"io"
8+
"os"
9+
"path/filepath"
10+
"testing"
11+
12+
loggerV2 "github.com/bitrise-io/go-utils/v2/log"
13+
pathutil2 "github.com/bitrise-io/go-utils/v2/pathutil"
14+
"github.com/bitrise-io/go-utils/v2/ziputil"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
func TestCollectFilesToDeploy_compressDir_producesZipWithContentsAndSymlink(t *testing.T) {
19+
srcDir := t.TempDir()
20+
tmpDir := t.TempDir()
21+
22+
require.NoError(t, os.WriteFile(filepath.Join(srcDir, "top.txt"), []byte("top"), 0644))
23+
require.NoError(t, os.MkdirAll(filepath.Join(srcDir, "sub"), 0755))
24+
require.NoError(t, os.WriteFile(filepath.Join(srcDir, "sub", "nested.txt"), []byte("nested"), 0644))
25+
require.NoError(t, os.Symlink("top.txt", filepath.Join(srcDir, "link.txt")))
26+
27+
config := Config{IsCompress: true}
28+
files, err := collectFilesToDeploy(srcDir, config, tmpDir, newZipManager(), loggerV2.NewLogger())
29+
require.NoError(t, err)
30+
31+
wantZip := filepath.Join(tmpDir, filepath.Base(srcDir)+".zip")
32+
require.Equal(t, []string{wantZip}, files)
33+
34+
entries := readZip(t, wantZip)
35+
require.Equal(t, "top", entries["top.txt"].content)
36+
require.Equal(t, "nested", entries["sub/nested.txt"].content)
37+
38+
// isContentOnly=true: entries are relative to srcDir, not prefixed with its basename.
39+
require.NotContains(t, entries, filepath.Base(srcDir)+"/top.txt")
40+
41+
// The symlink must be stored as a symlink pointing at its target, not followed and inlined.
42+
link, ok := entries["link.txt"]
43+
require.True(t, ok, "symlink entry missing from archive")
44+
require.True(t, link.mode&os.ModeSymlink != 0, "link.txt should be stored as a symlink")
45+
require.Equal(t, "top.txt", link.content)
46+
}
47+
48+
func TestCollectFilesToDeploy_compressDir_usesCustomZipName(t *testing.T) {
49+
srcDir := t.TempDir()
50+
tmpDir := t.TempDir()
51+
require.NoError(t, os.WriteFile(filepath.Join(srcDir, "a.txt"), []byte("a"), 0644))
52+
53+
config := Config{IsCompress: true, ZipName: "custom-name"}
54+
files, err := collectFilesToDeploy(srcDir, config, tmpDir, newZipManager(), loggerV2.NewLogger())
55+
require.NoError(t, err)
56+
require.Equal(t, []string{filepath.Join(tmpDir, "custom-name.zip")}, files)
57+
}
58+
59+
func TestCollectFilesToDeploy_compressEmptyDir_returnsNothing(t *testing.T) {
60+
config := Config{IsCompress: true}
61+
files, err := collectFilesToDeploy(t.TempDir(), config, t.TempDir(), newZipManager(), loggerV2.NewLogger())
62+
require.NoError(t, err)
63+
require.Empty(t, files)
64+
}
65+
66+
func TestCollectFilesToDeploy_uncompressedDir_listsFilesSkipsSubdirs(t *testing.T) {
67+
srcDir := t.TempDir()
68+
require.NoError(t, os.WriteFile(filepath.Join(srcDir, "a.txt"), []byte("a"), 0644))
69+
require.NoError(t, os.MkdirAll(filepath.Join(srcDir, "sub"), 0755))
70+
71+
config := Config{IsCompress: false}
72+
files, err := collectFilesToDeploy(srcDir, config, t.TempDir(), newZipManager(), loggerV2.NewLogger())
73+
require.NoError(t, err)
74+
require.Equal(t, []string{filepath.Join(srcDir, "a.txt")}, files)
75+
}
76+
77+
func newZipManager() *ziputil.ZipManager {
78+
return ziputil.NewZipManager(pathutil2.NewPathChecker())
79+
}
80+
81+
type zipEntry struct {
82+
content string
83+
mode os.FileMode
84+
}
85+
86+
func readZip(t *testing.T, zipPath string) map[string]zipEntry {
87+
t.Helper()
88+
r, err := zip.OpenReader(zipPath)
89+
require.NoError(t, err)
90+
defer r.Close()
91+
92+
entries := map[string]zipEntry{}
93+
for _, f := range r.File {
94+
if f.FileInfo().IsDir() {
95+
continue
96+
}
97+
rc, err := f.Open()
98+
require.NoError(t, err)
99+
content, err := io.ReadAll(rc)
100+
require.NoError(t, rc.Close())
101+
require.NoError(t, err)
102+
entries[f.Name] = zipEntry{content: string(content), mode: f.Mode()}
103+
}
104+
return entries
105+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ require (
99
github.com/bitrise-io/go-steputils v1.0.6
1010
github.com/bitrise-io/go-steputils/v2 v2.0.0-alpha.49
1111
github.com/bitrise-io/go-utils v1.0.15
12-
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.34
12+
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.36.0.20260612135825-fa80291d0871
1313
github.com/bitrise-io/go-xcode v1.3.3
1414
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.80
1515
github.com/docker/go-units v0.5.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ github.com/bitrise-io/go-utils v1.0.2/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0
2424
github.com/bitrise-io/go-utils v1.0.15 h1:KRQjNiPrkxBRM6G5fQy05v0p0r8wycWfKVb+Ko+Vtg0=
2525
github.com/bitrise-io/go-utils v1.0.15/go.mod h1:ZY1DI+fEpZuFpO9szgDeICM4QbqoWVt0RSY3tRI1heY=
2626
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.10/go.mod h1:Ta/ards3Ih/3Q6X8tBtcj6zTHcNf1hRSXv1E8lPgIYk=
27-
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.34 h1:xsLfhItfs4SCCAesbv7UtKpldNqievDvtHggSuBI2+w=
28-
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.34/go.mod h1:5Z/vkUZ2BIY7IAVlMGns3ypRjd+J872YBSCJaLWVo/U=
27+
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.36.0.20260612135825-fa80291d0871 h1:pYOZwG/04O9KIE+8/wbqQ4SXwLWm/6zFU+vV2BL9Ag4=
28+
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.36.0.20260612135825-fa80291d0871/go.mod h1:5Z/vkUZ2BIY7IAVlMGns3ypRjd+J872YBSCJaLWVo/U=
2929
github.com/bitrise-io/go-xcode v1.3.3 h1:aYkSMWP+1/n2ZabRy3OMfeaWmE4l1gAPq63azx06LIw=
3030
github.com/bitrise-io/go-xcode v1.3.3/go.mod h1:9OwsvrhZ4A2JxHVoEY7CPcABAKA+OE7FQqFfBfvbFuY=
3131
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.80 h1:/pq5C8nvn71HSsGyqhv76XcEgM/XZpYwMvBl4R+OczQ=

main.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import (
2727
"github.com/bitrise-io/go-utils/v2/fileutil"
2828
loggerV2 "github.com/bitrise-io/go-utils/v2/log"
2929
pathutil2 "github.com/bitrise-io/go-utils/v2/pathutil"
30-
"github.com/bitrise-io/go-utils/ziputil"
30+
"github.com/bitrise-io/go-utils/v2/ziputil"
3131
iosparser "github.com/bitrise-io/go-xcode/v2/metaparser"
3232
"github.com/bitrise-steplib/steps-deploy-to-bitrise-io/deployment"
3333
"github.com/bitrise-steplib/steps-deploy-to-bitrise-io/fileredactor"
@@ -142,6 +142,7 @@ func main() {
142142

143143
pathModifier := pathutil2.NewPathModifier()
144144
pathChecker := pathutil2.NewPathChecker()
145+
zipManager := ziputil.NewZipManager(pathChecker)
145146
pathProcessor := fileredactor.NewFilePathProcessor(pathModifier, pathChecker)
146147
filePaths, err := pathProcessor.ProcessFilePaths(config.FilesToRedact)
147148
if err != nil {
@@ -175,7 +176,7 @@ func main() {
175176
fail(logger, "Failed to expand path: %s, error: %s", config.DeployPath, err)
176177
}
177178

178-
filesToDeploy, err := collectFilesToDeploy(absDeployPth, config, tmpDir, logger)
179+
filesToDeploy, err := collectFilesToDeploy(absDeployPth, config, tmpDir, zipManager, logger)
179180
if err != nil {
180181
fail(logger, "%s", err)
181182
}
@@ -186,7 +187,7 @@ func main() {
186187
if strings.TrimSpace(config.PipelineIntermediateFiles) != "" {
187188
zipComparator := deployment.NewZipComparator(deployment.DefaultReadZipFunction)
188189
repository := env.NewRepository()
189-
collector := deployment.NewCollector(zipComparator, deployment.DefaultIsDirFunction, ziputil.ZipDir, repository, tmpDir)
190+
collector := deployment.NewCollector(zipComparator, deployment.DefaultIsDirFunction, zipManager.ZipDir, repository, tmpDir)
190191
deployableItems, err = collector.AddIntermediateFiles(deployableItems, config.PipelineIntermediateFiles)
191192
if err != nil {
192193
fail(logger, "%s", err)
@@ -390,7 +391,7 @@ func clearDeployFiles(filesToDeploy []string, logger loggerV2.Logger) []string {
390391
return clearedFilesToDeploy
391392
}
392393

393-
func collectFilesToDeploy(absDeployPth string, config Config, tmpDir string, logger loggerV2.Logger) (filesToDeploy []string, err error) {
394+
func collectFilesToDeploy(absDeployPth string, config Config, tmpDir string, zipManager *ziputil.ZipManager, logger loggerV2.Logger) (filesToDeploy []string, err error) {
394395
pathExists, err := pathutil.IsPathExists(absDeployPth)
395396
if err != nil {
396397
return nil, fmt.Errorf("failed to check if %s exists: %s", absDeployPth, err)
@@ -427,7 +428,7 @@ func collectFilesToDeploy(absDeployPth string, config Config, tmpDir string, log
427428
}
428429
tmpZipPath := filepath.Join(tmpDir, zipName+".zip")
429430

430-
if err := ziputil.ZipDir(absDeployPth, tmpZipPath, true); err != nil {
431+
if err := zipManager.ZipDir(absDeployPth, tmpZipPath, true); err != nil {
431432
return nil, fmt.Errorf("failed to zip output dir, error: %s", err)
432433
}
433434

vendor/github.com/bitrise-io/go-utils/v2/env/env.go

Lines changed: 122 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/bitrise-io/go-utils/v2/fileutil/copy.go

Lines changed: 18 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/bitrise-io/go-utils/v2/fileutil/fileutil.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)