Skip to content

Commit

Permalink
upgrade editor version if a new version is available
Browse files Browse the repository at this point in the history
  • Loading branch information
zulkhair committed Apr 4, 2024
1 parent 0dfd522 commit 9208f6a
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 16 deletions.
15 changes: 5 additions & 10 deletions cmd/world/cardinal/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,16 +285,11 @@ func runCardinalEditor(port int, prepChan chan struct{}) error {
}
cardinalEditorDir := filepath.Join(workingDir, teacmd.TargetEditorDir)

// TODO: Check the version of cardinal and match it with cardinal editor version

// Check if the Cardinal Editor directory exists
if _, err := os.Stat(cardinalEditorDir); os.IsNotExist(err) {
// Setup cardinal editor
err = teacmd.SetupCardinalEditor()
if err != nil {
prepChan <- struct{}{}
return err
}
// Setup cardinal editor
err = teacmd.SetupCardinalEditor()
if err != nil {
prepChan <- struct{}{}
return err
}

// Serve cardinal editor dir
Expand Down
106 changes: 101 additions & 5 deletions common/teacmd/editor.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,36 @@ import (
"time"

"github.com/google/uuid"
"github.com/rotisserie/eris"
"golang.org/x/mod/modfile"

"pkg.world.dev/world-cli/common/globalconfig"
)

const (
TargetEditorDir = ".editor"

latestReleaseURL = "https://api.github.com/repos/Argus-Labs/cardinal-editor/releases/latest"
httpTimeout = 2 * time.Second
releaseURL = "https://api.github.com/repos/Argus-Labs/cardinal-editor/releases"
latestReleaseURL = releaseURL + "/latest"

httpTimeout = 2 * time.Second

cardinalProjectIDPlaceholder = "__CARDINAL_PROJECT_ID__"

cardinalGomodPath = "cardinal/go.mod"

cardinalPkgPath = "pkg.world.dev/world-engine/cardinal"
)

var (
// Cardinal : Cardinal Editor version map
// TODO this version map need to store in somewhere that can be accessed online
cardinalVersionMap = map[string]string{
"v1.2.2-beta": "v0.1.0",
"v1.2.3-beta": "v0.1.0",
"v1.2.4-beta": "v0.3.0",
"v1.2.5-beta": "v0.3.0",
}
)

type Asset struct {
Expand All @@ -36,12 +56,36 @@ type Release struct {
}

func SetupCardinalEditor() error {
// Check version
cardinalVersion, err := getModuleVersion(cardinalGomodPath, cardinalPkgPath)
if err != nil {
return eris.Wrap(err, "failed to get cardinal version")

Check warning on line 62 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L60-L62

Added lines #L60 - L62 were not covered by tests
}

downloadURL := latestReleaseURL
downloadVersion, versionIsExist := cardinalVersionMap[cardinalVersion]
if versionIsExist {
downloadURL = fmt.Sprintf("%s/tags/%s", releaseURL, downloadVersion)

Check warning on line 68 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L65-L68

Added lines #L65 - L68 were not covered by tests
}

// Check if the Cardinal Editor directory exists
if _, err := os.Stat(TargetEditorDir); !os.IsNotExist(err) {

Check warning on line 72 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L72

Added line #L72 was not covered by tests
// Check the version of cardinal editor is appropriate
if fileExists(filepath.Join(TargetEditorDir, downloadVersion)) {

Check warning on line 74 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L74

Added line #L74 was not covered by tests
// do nothing if the version is already downloaded
return nil

Check warning on line 76 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L76

Added line #L76 was not covered by tests
}

// Remove the existing Cardinal Editor directory
os.RemoveAll(TargetEditorDir)

Check warning on line 80 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L80

Added line #L80 was not covered by tests
}

configDir, err := globalconfig.GetConfigDir()
if err != nil {
return err
}

editorDir, err := downloadReleaseIfNotCached(configDir)
editorDir, err := downloadReleaseIfNotCached(downloadURL, configDir)

Check warning on line 88 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L88

Added line #L88 was not covered by tests
if err != nil {
return err
}
Expand All @@ -60,11 +104,17 @@ func SetupCardinalEditor() error {
return err
}

// this file is used to check if the version is already downloaded
err = addFileVersion(filepath.Join(TargetEditorDir, downloadVersion))
if err != nil {
return err

Check warning on line 110 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L108-L110

Added lines #L108 - L110 were not covered by tests
}

return nil
}

func downloadReleaseIfNotCached(configDir string) (string, error) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, latestReleaseURL, nil)
func downloadReleaseIfNotCached(downloadURL, configDir string) (string, error) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, downloadURL, nil)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -270,3 +320,49 @@ func strippedGUID() string {
u := uuid.New()
return strings.ReplaceAll(u.String(), "-", "")
}

// addFileVersion add file with name version of cardinal editor
func addFileVersion(version string) error {
// Create the file
file, err := os.Create(version)
if err != nil {
return err
}
defer file.Close()

return nil
}

func getModuleVersion(gomodPath, modulePath string) (string, error) {
// Read the go.mod file
data, err := os.ReadFile(gomodPath)
if err != nil {
return "", err
}

// Parse the go.mod file
modFile, err := modfile.Parse(gomodPath, data, nil)
if err != nil {
return "", err

Check warning on line 346 in common/teacmd/editor.go

View check run for this annotation

Codecov / codecov/patch

common/teacmd/editor.go#L346

Added line #L346 was not covered by tests
}

// Iterate through the require statements to find the desired module
for _, require := range modFile.Require {
if require.Mod.Path == modulePath {
return require.Mod.Version, nil
}
}

// Return an error if the module is not found
return "", fmt.Errorf("module %s not found", modulePath)
}

// fileExists checks if a file exists and is not a directory before we
// try using it to prevent further errors.
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
134 changes: 133 additions & 1 deletion common/teacmd/editor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestSetupCardinalEditor(t *testing.T) {
t.Run("setup cardinal editor", func(t *testing.T) {
cleanUpDir(testDir)

editorDir, err := downloadReleaseIfNotCached(testDir)
editorDir, err := downloadReleaseIfNotCached(latestReleaseURL, testDir)
assert.NilError(t, err)

// check if editor directory exists
Expand Down Expand Up @@ -129,3 +129,135 @@ func TestStrippedGUID(t *testing.T) {
assert.Check(t, !strings.Contains(s, "-"))
})
}

func TestAddFileVersion(t *testing.T) {
testCases := []struct {
version string
shouldFail bool
}{
{"v0.1.0", false},
{"/v1.0.1", true},
}

for _, tc := range testCases {
err := addFileVersion(tc.version)

if tc.shouldFail && err == nil {
t.Errorf("Expected addFileVersion to fail for version '%s', but it didn't", tc.version)
} else if !tc.shouldFail {
if err != nil {
t.Errorf("addFileVersion failed for version '%s': %s", tc.version, err)
}

// Check if file exists
_, err = os.Stat(tc.version)
if os.IsNotExist(err) {
t.Errorf("file %s was not created", tc.version)
}

// Cleanup
err = os.Remove(tc.version)
if err != nil {
t.Logf("Failed to delete test file '%s': %s", tc.version, err)
}
}
}
}

func TestGetModuleVersion(t *testing.T) {
// Setup temporary go.mod file for testing
gomodContent := `
module example.com/mymodule
go 1.21.1
require (
pkg.world.dev/world-engine/cardinal v1.2.3-beta
github.com/moduleexample/v3 v3.2.1
)
`
gomodPath := "./test-go.mod"
err := os.WriteFile(gomodPath, []byte(gomodContent), 0644)
if err != nil {
t.Fatal(err)
}
defer os.Remove(gomodPath) // clean up

tests := []struct {
name string
gomodPath string
modulePath string
wantVersion string
expectError bool
}{
{
name: "Module exists",
gomodPath: gomodPath,
modulePath: "pkg.world.dev/world-engine/cardinal",
wantVersion: "v1.2.3-beta",
expectError: false,
},
{
name: "Module does not exist",
gomodPath: gomodPath,
modulePath: "nonexistent/module",
wantVersion: "",
expectError: true,
},
{
name: "go.mod file does not exist",
gomodPath: "./nonexistent-go.mod",
modulePath: "github.com/moduleexample",
wantVersion: "",
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
version, err := getModuleVersion(tt.gomodPath, tt.modulePath)
if (err != nil) != tt.expectError {
t.Errorf("getModuleVersion() error = %v, expectError %v", err, tt.expectError)
return
}
if version != tt.wantVersion {
t.Errorf("getModuleVersion() = %v, want %v", version, tt.wantVersion)
}
})
}
}

func TestFileExists(t *testing.T) {
// Create a temporary file and defer its removal
tempFile, err := os.CreateTemp("", "example")
if err != nil {
t.Fatalf("Unable to create temporary file: %s", err)
}
defer os.Remove(tempFile.Name())

// Test case where the file does exist
if exists := fileExists(tempFile.Name()); !exists {
t.Errorf("fileExists(%s) = %v, want %v", tempFile.Name(), exists, true)
}

// Remove the file to simulate it not existing
tempFile.Close()
os.Remove(tempFile.Name())

// Test case where the file does not exist
if exists := fileExists(tempFile.Name()); exists {
t.Errorf("fileExists(%s) = %v, want %v", tempFile.Name(), exists, false)
}

// Create a temporary directory and defer its removal
tempDir, err := os.MkdirTemp("", "example")
if err != nil {
t.Fatalf("Unable to create temporary directory: %s", err)
}
defer os.RemoveAll(tempDir)

// Test case where the path is a directory
if exists := fileExists(tempDir); exists {
t.Errorf("fileExists(%s) = %v, want %v", tempDir, exists, false)
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/rotisserie/eris v0.5.4
github.com/rs/zerolog v1.31.0
github.com/spf13/cobra v1.7.0
golang.org/x/mod v0.16.0
gotest.tools/v3 v3.5.1
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down

0 comments on commit 9208f6a

Please sign in to comment.