Skip to content

Commit

Permalink
Merge pull request #29 from hathora/prelaunch-cleanup-4
Browse files Browse the repository at this point in the history
Prelaunch bug-fixes
  • Loading branch information
drewfead authored Jun 14, 2024
2 parents 97b7fc7 + 3ce61fb commit 9a38eb5
Show file tree
Hide file tree
Showing 12 changed files with 348 additions and 160 deletions.
2 changes: 1 addition & 1 deletion install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ Invoke-WebRequest -Uri $downloadUrl -OutFile "$binaryName.exe"

# Install the binary
Write-Host "Installing $binaryName to $installDir..."
Move-Item -Path "$binaryName.exe" -Destination $installDir
Move-Item -Path "$binaryName.exe" -Destination $installDir -Force

Write-Host "Installation complete!"
20 changes: 13 additions & 7 deletions internal/archive/targz.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func shouldIgnoreFilepath(filepath string, isDir bool, matchers []gitignore.Igno
return anyMatches
}

func ArchiveTGZ(srcFolder string) (string, error) {
func CreateTGZ(srcFolder string) (string, error) {
fileName := filepath.Base(filepath.Clean(srcFolder))
destinationFile := fmt.Sprintf("%s.*.tgz", fileName)
tarGzFile, err := os.CreateTemp("", destinationFile)
Expand Down Expand Up @@ -82,21 +82,22 @@ func ArchiveTGZ(srcFolder string) (string, error) {
}

if shouldIgnoreFilepath(relPath, info.IsDir(), ignoreMatchers) {
zap.L().Debug("Ignoring file: " + relPath)
return nil
}

header, err := tar.FileInfoHeader(info, relPath)
header, err := tar.FileInfoHeader(info, "")
if err != nil {
return err
}

header.Name = relPath
header.Name = filepath.ToSlash(relPath)

if err := tarWriter.WriteHeader(header); err != nil {
return err
}

if info.IsDir() {
zap.L().Debug("Including directory reference: " + relPath)
return nil
}

Expand All @@ -106,10 +107,15 @@ func ArchiveTGZ(srcFolder string) (string, error) {
}
defer file.Close()

if _, err := io.Copy(tarWriter, file); err != nil {
return err
written, err := io.Copy(tarWriter, file)
if err != nil {
return fmt.Errorf("error copying file content for %s: %w", filePath, err)
}
if written != info.Size() {
return fmt.Errorf("expected to write %d bytes but wrote %d bytes for file %s", info.Size(), written, filePath)
}

zap.L().Debug("Inlcluding file: " + relPath)
return nil
})

Expand Down Expand Up @@ -181,7 +187,7 @@ func RequireTGZ(srcFolder string) (*TGZFile, error) {

zap.L().Debug(srcFolder + " is not a gzipped tar archive. Archiving and compressing now.")

destFile, err := ArchiveTGZ(srcFolder)
destFile, err := CreateTGZ(srcFolder)
if err != nil {
return nil, err
}
Expand Down
139 changes: 139 additions & 0 deletions internal/archive/targz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package archive_test

import (
"archive/tar"
"compress/gzip"
"io"
"os"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"

"github.com/hathora/ci/internal/archive"
)

func Test_CreateTGZ(t *testing.T) {
zapLogger, _ := zap.NewDevelopment()
zap.ReplaceGlobals(zapLogger)
tests := []struct {
name string
files map[string]string
shouldFail bool
}{
{
name: "simple",
files: map[string]string{
"file1.txt": "This is file 1",
"subdir/file2.txt": "This is file 2 in subdir",
},
shouldFail: false,
},
{
name: "nested",
files: map[string]string{
"dir1/dir2/file3.txt": "This is file 3 in nested directory",
"dir1/file4.txt": "This is file 4",
},
shouldFail: false,
},
{
name: "nested with dirs only",
files: map[string]string{
"dir3/": "",
"dir3/dir4/": "",
"dir3/dir4/file5.txt": "This is file 5 in nested empty directory",
},
shouldFail: false,
},
{
name: "special characters in filenames",
files: map[string]string{
"file with spaces.txt": "This is a file with spaces",
"file-with-üñîçødé.txt": "This file has unicode characters",
},
shouldFail: false,
},
{
name: "empty",
files: map[string]string{},
shouldFail: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert := assert.New(t)

srcFolder, err := os.MkdirTemp("", "testsrc")
require.NoError(t, err)
t.Cleanup(func() {
os.RemoveAll(srcFolder)
})

for path, content := range tt.files {
fullPath := filepath.Join(srcFolder, path)
if strings.HasSuffix(path, "/") {
require.NoError(t, os.MkdirAll(fullPath, os.ModePerm))
} else {
err := os.MkdirAll(filepath.Dir(fullPath), os.ModePerm)
require.NoError(t, err)
err = os.WriteFile(fullPath, []byte(content), 0644)
require.NoError(t, err)
}
}

archivePath, err := archive.CreateTGZ(srcFolder)
if tt.shouldFail {
assert.Error(err)
return
} else {
assert.NoError(err)
}
t.Cleanup(func() {
os.Remove(archivePath)
})

file, err := os.Open(archivePath)
assert.NoError(err)
t.Cleanup(func() {
file.Close()
})

gzipReader, err := gzip.NewReader(file)
assert.NoError(err)
t.Cleanup(func() {
gzipReader.Close()
})

tarReader := tar.NewReader(gzipReader)

archivedFiles := make(map[string]string)
for {
header, err := tarReader.Next()
if err == io.EOF {
break
}
assert.NoError(err)

if header.Typeflag == tar.TypeReg {
content, err := io.ReadAll(tarReader)
assert.NoError(err)
archivedFiles[header.Name] = string(content)
}
}

for path, expectedContent := range tt.files {
if strings.HasSuffix(path, "/") {
continue // Skip directories
}
content, found := archivedFiles[path]
assert.True(found, "Expected file %s not found in archive", path)
assert.Equal(expectedContent, content, "File content mismatch for %s", path)
}
})
}
}
35 changes: 23 additions & 12 deletions internal/commands/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,33 @@ var (
BuildVersion = "unknown"
)

func App() *cli.Command {
func init() {
cli.VersionFlag = &cli.BoolFlag{
Name: "version",
Usage: "print the version",
Name: "version",
Usage: "print the version",
Category: "Global:",
}

cli.HelpFlag = &cli.BoolFlag{
Name: "help",
Aliases: []string{"h"},
Usage: "show help",
Category: "Global:",
}
}

func App() *cli.Command {
var cleanup []func()
return &cli.Command{
Name: "hathora",
EnableShellCompletion: true,
Suggest: true,
UseShortOptionHandling: true,
SliceFlagSeparator: ",",
Usage: "a CLI tool for for CI/CD workflows to manage deployments and builds in hathora.dev",
Flags: GlobalFlags,
Version: BuildVersion,
Name: "hathora",
EnableShellCompletion: true,
Suggest: true,
UseShortOptionHandling: true,
SliceFlagSeparator: ",",
Usage: "a CLI tool for for CI/CD workflows to manage deployments and builds in hathora.dev",
Flags: GlobalFlags,
Version: BuildVersion,
CustomRootCommandHelpTemplate: cli.SubcommandHelpTemplate,
Before: func(ctx context.Context, cmd *cli.Command) error {
handleNewVersionAvailable(BuildVersion)

Expand All @@ -40,7 +51,7 @@ func App() *cli.Command {
if err != nil {
return err
}
cfg, err := GlobalConfigFrom(cmd)
cfg, err := VerbosityConfigFrom(cmd)
if err != nil {
return err
}
Expand Down
25 changes: 16 additions & 9 deletions internal/commands/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ var Build = &cli.Command{
cli.ShowSubcommandHelp(cmd)
return err
}
created, err := doBuildCreate(ctx, build)
created, err := doBuildCreate(ctx, build.SDK, build.AppID, build.BuildTag, build.FilePath)
if err != nil {
return err
}
Expand Down Expand Up @@ -119,24 +119,24 @@ var Build = &cli.Command{
},
}

func doBuildCreate(ctx context.Context, build *CreateBuildConfig) (*shared.Build, error) {
createRes, err := build.SDK.BuildV2.CreateBuild(
func doBuildCreate(ctx context.Context, hathora *sdk.SDK, appID *string, buildTag, filePath string) (*shared.Build, error) {
createRes, err := hathora.BuildV2.CreateBuild(
ctx,
shared.CreateBuildParams{
BuildTag: sdk.String(build.BuildTag),
BuildTag: sdk.String(buildTag),
},
build.AppID,
appID,
)
if err != nil {
return nil, fmt.Errorf("failed to create a build: %w", err)
}

file, err := archive.RequireTGZ(build.FilePath)
file, err := archive.RequireTGZ(filePath)
if err != nil {
return nil, fmt.Errorf("no build file available for run: %w", err)
}

runRes, err := build.SDK.BuildV2.RunBuild(
runRes, err := hathora.BuildV2.RunBuild(
ctx,
createRes.Build.BuildID,
operations.RunBuildRequestBody{
Expand All @@ -145,7 +145,7 @@ func doBuildCreate(ctx context.Context, build *CreateBuildConfig) (*shared.Build
Content: file.Content,
},
},
build.AppID,
appID,
)

if err != nil {
Expand Down Expand Up @@ -211,7 +211,8 @@ var (

type BuildConfig struct {
*GlobalConfig
SDK *sdk.SDK
SDK *sdk.SDK
Output output.FormatWriter
}

var _ LoadableConfig = (*BuildConfig)(nil)
Expand All @@ -223,6 +224,12 @@ func (c *BuildConfig) Load(cmd *cli.Command) error {
}
c.GlobalConfig = global
c.SDK = setup.SDK(c.Token, c.BaseURL, c.Verbosity)
var build shared.Build
output, err := OutputFormatterFor(cmd, build)
if err != nil {
return err
}
c.Output = output
return nil
}

Expand Down
Loading

0 comments on commit 9a38eb5

Please sign in to comment.