diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 33e928fc91..e96dba2d76 100755 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: # === OS Specific Job (runs on each OS) === os_specific: name: ${{ matrix.sys.os }} - timeout-minutes: 90 + timeout-minutes: 120 strategy: matrix: go-version: @@ -327,7 +327,7 @@ jobs: export TEST_SUITE_TAGS="$TEST_SUITE_TAGS" TIMEOUT=30m if [[ "$TEST_SUITE_TAGS" == "all" ]]; then - TIMEOUT=90m + TIMEOUT=120m fi SHELL='${{ matrix.sys.shell }}' go test -timeout $TIMEOUT -v `go list ./... | grep "integration"` -json 2>&1 | gotestfmt -hide empty-packages continue-on-error: ${{ github.event_name == 'schedule' }} @@ -335,7 +335,6 @@ jobs: INTEGRATION_TEST_USERNAME: ${{ secrets.INTEGRATION_TEST_USERNAME }} INTEGRATION_TEST_PASSWORD: ${{ secrets.INTEGRATION_TEST_PASSWORD }} INTEGRATION_TEST_TOKEN: ${{ secrets.INTEGRATION_TEST_TOKEN }} - PLATFORM_API_TOKEN: ${{ secrets.PLATFORM_API_TOKEN }} - # === Check if Unit Tests Failed === name: Check if Unit Tests Failed diff --git a/changelog.md b/changelog.md index fde7948ab8..f7a7fb8fb9 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ and this project adheres to ### Fixed - Fixed occasional panic due to a concurrent map read/write during runtime setup. +- Fixed `state clean cache` from accidentally deleting State Tool binaries on Windows. ## 0.48.0 diff --git a/cmd/state-svc/main.go b/cmd/state-svc/main.go index 6a30ab9380..5f9d905092 100644 --- a/cmd/state-svc/main.go +++ b/cmd/state-svc/main.go @@ -55,7 +55,10 @@ func main() { } if err := events.WaitForEvents(5*time.Second, rollbar.Wait, authentication.LegacyClose, logging.Close); err != nil { - logging.Warning("Failing to wait events") + // Note: logger is closed, so cannot log here. Also, the activate integration tests seem to be + // affected by a write to os.Stderr. Regardless, since state-svc runs in the background for + // the most part, we realistically will not see this error. + //fmt.Fprintf(os.Stderr, "Warning: failed to wait for events") } os.Exit(exitCode) }() diff --git a/cmd/state-svc/test/integration/svc_int_test.go b/cmd/state-svc/test/integration/svc_int_test.go index 41fcfd22e3..d00cfa25f6 100644 --- a/cmd/state-svc/test/integration/svc_int_test.go +++ b/cmd/state-svc/test/integration/svc_int_test.go @@ -157,7 +157,10 @@ func (suite *SvcIntegrationTestSuite) TestStartDuplicateErrorOutput() { func (suite *SvcIntegrationTestSuite) TestSingleSvc() { suite.OnlyRunForTags(tagsuite.Service) ts := e2e.New(suite.T(), false) - defer ts.Close() + // TODO: CP-1268 should remove this conditional. + if runtime.GOOS != "windows" || !condition.OnCI() { + defer ts.Close() + } ts.SpawnCmdWithOpts(ts.SvcExe, e2e.OptArgs("stop")) time.Sleep(2 * time.Second) // allow for some time to stop the existing available process diff --git a/internal/installation/storage/storage.go b/internal/installation/storage/storage.go index cfc1772617..dde30e6ca5 100644 --- a/internal/installation/storage/storage.go +++ b/internal/installation/storage/storage.go @@ -105,7 +105,13 @@ func CachePath() string { return path } - return filepath.Join(BaseCachePath(), relativeCachePath()) + cachePath = filepath.Join(BaseCachePath(), relativeCachePath()) + if runtime.GOOS == "windows" { + // Explicitly append "cache" dir as the cachedir on Windows. + // It is the same as the local appdata dir (conflicts with config) + cachePath = filepath.Join(cachePath, "cache") + } + return cachePath } func GlobalBinDir() string { diff --git a/internal/installation/storage/storage_windows.go b/internal/installation/storage/storage_windows.go index 4a4986440a..861b69075d 100644 --- a/internal/installation/storage/storage_windows.go +++ b/internal/installation/storage/storage_windows.go @@ -18,5 +18,5 @@ func BaseCachePath() string { return cache } - return filepath.Join(homeDir, "AppData", "Local", "cache") + return filepath.Join(homeDir, "AppData", "Local") } diff --git a/internal/testhelpers/e2e/clean.go b/internal/testhelpers/e2e/clean.go index 7a8cd9246f..273f6d50eb 100644 --- a/internal/testhelpers/e2e/clean.go +++ b/internal/testhelpers/e2e/clean.go @@ -1,31 +1,12 @@ package e2e import ( - "testing" - "github.com/ActiveState/cli/internal/errs" "github.com/ActiveState/cli/pkg/platform/api/mono/mono_client/projects" - "github.com/ActiveState/cli/pkg/platform/api/mono/mono_client/users" "github.com/ActiveState/cli/pkg/platform/api/mono/mono_models" "github.com/ActiveState/cli/pkg/platform/authentication" - "github.com/ActiveState/cli/pkg/platform/model" ) -func cleanUser(t *testing.T, username string, auth *authentication.Auth) error { - projects, err := getProjects(username, auth) - if err != nil { - return err - } - for _, proj := range projects { - err = model.DeleteProject(username, proj.Name, auth) - if err != nil { - return err - } - } - - return deleteUser(username, auth) -} - func getProjects(org string, auth *authentication.Auth) ([]*mono_models.Project, error) { authClient, err := auth.Client() if err != nil { @@ -40,20 +21,3 @@ func getProjects(org string, auth *authentication.Auth) ([]*mono_models.Project, return listProjectsOK.Payload, nil } - -func deleteUser(name string, auth *authentication.Auth) error { - authClient, err := auth.Client() - if err != nil { - return errs.Wrap(err, "Could not get auth client") - } - - params := users.NewDeleteUserParams() - params.SetUsername(name) - - _, err = authClient.Users.DeleteUser(params, auth.ClientAuth()) - if err != nil { - return err - } - - return nil -} diff --git a/internal/testhelpers/e2e/session.go b/internal/testhelpers/e2e/session.go index 56ddc8647e..99d493f66b 100644 --- a/internal/testhelpers/e2e/session.go +++ b/internal/testhelpers/e2e/session.go @@ -56,8 +56,6 @@ type Session struct { Env []string retainDirs bool createdProjects []*project.Namespaced - // users created during session - users []string T *testing.T Exe string SvcExe string @@ -542,11 +540,6 @@ func (s *Session) Close() error { s.spawned = []*SpawnedCmd{} - if os.Getenv("PLATFORM_API_TOKEN") == "" { - s.T.Log("PLATFORM_API_TOKEN env var not set, not running suite tear down") - return nil - } - auth := authentication.New(cfg) if os.Getenv(constants.APIHostEnvVarName) == "" { @@ -560,9 +553,11 @@ func (s *Session) Close() error { } err = auth.AuthenticateWithModel(&mono_models.Credentials{ - Token: os.Getenv("PLATFORM_API_TOKEN"), + Username: PersistentUsername, + Password: PersistentPassword, }) if err != nil { + s.T.Errorf("Could not login: %v", errs.JoinMessage(err)) return err } @@ -586,14 +581,7 @@ func (s *Session) Close() error { for _, proj := range s.createdProjects { err := model.DeleteProject(proj.Owner, proj.Project, auth) if err != nil { - s.T.Errorf("Could not delete project %s: %v", proj.Project, errs.JoinMessage(err)) - } - } - - for _, user := range s.users { - err := cleanUser(s.T, user, auth) - if err != nil { - s.T.Errorf("Could not delete user %s: %v", user, errs.JoinMessage(err)) + s.T.Errorf("Could not delete project %s/%s: %v", proj.Owner, proj.Project, errs.JoinMessage(err)) } } @@ -799,7 +787,7 @@ func (s *Session) SetupRCFileCustom(subshell subshell.SubShell) { rcFile, err := subshell.RcFile() require.NoError(s.T, err) - if fileutils.TargetExists(filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) { + if fileutils.TargetExists(rcFile) && fileutils.TargetExists(filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) { err = fileutils.CopyFile(rcFile, filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) } else { err = fileutils.Touch(filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) diff --git a/test/integration/buildscript_int_test.go b/test/integration/buildscript_int_test.go index df94e9f05b..22d2b9339f 100644 --- a/test/integration/buildscript_int_test.go +++ b/test/integration/buildscript_int_test.go @@ -179,7 +179,7 @@ func (suite *BuildScriptIntegrationTestSuite) TestBuildScriptRequirementVersionA cp.ExpectExitCode(0) cp = ts.Spawn("install", "dotenv") - cp.Expect("Added: language/python/dotenv@Auto") + cp.Expect("Added: language/python/dotenv@Auto", e2e.RuntimeSolvingTimeoutOpt) cp.ExpectExitCode(0) } diff --git a/test/integration/commit_int_test.go b/test/integration/commit_int_test.go index 6d96e05453..4e93f1e5d6 100644 --- a/test/integration/commit_int_test.go +++ b/test/integration/commit_int_test.go @@ -67,7 +67,7 @@ func (suite *CommitIntegrationTestSuite) TestCommitAtTimeChange() { ts := e2e.New(suite.T(), false) defer ts.Close() - ts.PrepareProjectAndBuildScript("ActiveState-CLI/Commit-Test-A", "7a1b416e-c17f-4d4a-9e27-cbad9e8f5655") + ts.PrepareProjectAndBuildScript("ActiveState-CLI/Commit-Test-A", "2ab50eba-4410-4be2-ba9d-c04ebeda640d") proj, err := project.FromPath(ts.Dirs.Work) suite.NoError(err, "Error loading project") @@ -76,11 +76,11 @@ func (suite *CommitIntegrationTestSuite) TestCommitAtTimeChange() { suite.Require().NoError(err) // verify validity // Update top-level at_time variable. - dateTime := "2023-06-21T12:34:56Z" + dateTime := "2025-12-11T12:34:56Z" buildScriptFile := filepath.Join(proj.Dir(), constants.BuildScriptFileName) contents, err := fileutils.ReadFile(buildScriptFile) suite.Require().NoError(err) - contents = bytes.Replace(contents, []byte("2023-06-22T21:56:10Z"), []byte(dateTime), 1) + contents = bytes.Replace(contents, []byte("2025-12-10T17:03:26Z"), []byte(dateTime), 1) suite.Require().NoError(fileutils.WriteFile(buildScriptFile, contents)) suite.Require().Contains(string(fileutils.ReadFileUnsafe(filepath.Join(proj.Dir(), constants.BuildScriptFileName))), dateTime) @@ -152,14 +152,16 @@ func (suite *CommitIntegrationTestSuite) TestCommitSkipValidation() { suite.Require().NoError(fileutils.WriteFile(scriptPath, data)) cp := ts.Spawn("commit") - cp.Expect("solver_version in body should be") + cp.Expect("solver_version") + cp.Expect("should be") cp.ExpectExitCode(1) cp = ts.Spawn("commit", "--skip-validation") cp.ExpectExitCode(0) cp = ts.Spawn("refresh") - cp.Expect("solver_version in body should be") + cp.Expect("solver_version") + cp.Expect("should be") cp.ExpectExitCode(1) } diff --git a/test/integration/install_int_test.go b/test/integration/install_int_test.go index eb939642ca..5bc9e139b5 100644 --- a/test/integration/install_int_test.go +++ b/test/integration/install_int_test.go @@ -2,6 +2,7 @@ package integration import ( "path/filepath" + "runtime" "strings" "testing" @@ -40,10 +41,15 @@ func (suite *InstallIntegrationTestSuite) TestInstallSuggest() { cp := ts.Spawn("config", "set", constants.AsyncRuntimeConfig, "true") cp.ExpectExitCode(0) - cp = ts.Spawn("install", "djang") + package_name := "djang" + if runtime.GOOS == "linux" { + // For some reason, "djang" on Linux often fails to show suggestions. + package_name = "jinj" + } + cp = ts.Spawn("install", package_name) cp.Expect("No results found", e2e.RuntimeSolvingTimeoutOpt) cp.Expect("Did you mean") - cp.Expect("language/python/djang") + cp.Expect("language/python/" + package_name) cp.ExpectExitCode(1) } diff --git a/test/integration/package_int_test.go b/test/integration/package_int_test.go index d0e5a6cdcc..81b45d9a0b 100644 --- a/test/integration/package_int_test.go +++ b/test/integration/package_int_test.go @@ -679,12 +679,14 @@ func (suite *PackageIntegrationTestSuite) TestChangeSummary() { cp.Expect("Successfully set") cp.ExpectExitCode(0) - ts.PrepareProject("ActiveState-CLI/small-python", "5a1e49e5-8ceb-4a09-b605-ed334474855b") + ts.PrepareProject("ActiveState-CLI/small-python", "66f0259d-5d7a-48ce-a814-fd9db46c5ce6") cp = ts.Spawn("install", "requests@2.31.0") cp.Expect("Resolving Dependencies") cp.Expect("Done") - cp.Expect("Installing requests@2.31.0 includes 4 direct dependencies") + cp.Expect("Installing") + cp.Expect("requests@2.31.0") + cp.Expect("includes 4 direct dependencies") cp.Expect("├─ ") cp.Expect("├─ ") cp.Expect("├─ ") diff --git a/test/integration/platforms_int_test.go b/test/integration/platforms_int_test.go index 9fb5860e99..08f3422bda 100644 --- a/test/integration/platforms_int_test.go +++ b/test/integration/platforms_int_test.go @@ -44,11 +44,12 @@ func (suite *PlatformsIntegrationTestSuite) TestPlatforms_listSimple() { {"platforms"}, {"platforms", "search"}, } + for _, cmd := range cmds { cp := ts.Spawn(cmd...) expectations := []string{ - "Linux", - "4.18.0", + "Windows", + "10", "x86", "64", } diff --git a/test/integration/revert_int_test.go b/test/integration/revert_int_test.go index 14aef5b663..7482efb036 100644 --- a/test/integration/revert_int_test.go +++ b/test/integration/revert_int_test.go @@ -24,10 +24,10 @@ func (suite *RevertIntegrationTestSuite) TestRevert() { defer ts.Close() namespace := "ActiveState-CLI/Revert" - ts.PrepareProject(namespace, "903bf49a-6719-47f0-ae70-450d69532ece") + ts.PrepareProject(namespace, "ca615135-ef95-4392-aff5-85b6c7132789") // Revert the commit that added urllib3. - commitID := "1f4f4f7d-7883-400e-b2ad-a5803c018ecd" + commitID := "c44885ee-af0e-4f52-b8ef-63c56fe255c6" cp := ts.Spawn("revert", commitID) cp.Expect(fmt.Sprintf("Operating on project %s", namespace)) cp.Expect("You are about to revert the following commit:") @@ -48,7 +48,7 @@ func (suite *RevertIntegrationTestSuite) TestRevert() { cp = ts.Spawn("shell", "Revert") cp.ExpectInput(e2e.RuntimeSourcingTimeoutOpt) cp.SendLine("python3") - cp.Expect("3.9.15") + cp.Expect("3.11.12") cp.SendLine("import urllib3") cp.Expect("No module named 'urllib3'") cp.SendLine("import argparse") @@ -63,7 +63,7 @@ func (suite *RevertIntegrationTestSuite) TestRevertRemote() { ts := e2e.New(suite.T(), false) defer ts.Close() - ts.PrepareProject("ActiveState-CLI/Revert", "75ae9c67-df55-4a95-be6f-b7975e5bb523") + ts.PrepareProject("ActiveState-CLI/Revert", "ca615135-ef95-4392-aff5-85b6c7132789") cp := ts.Spawn("config", "set", constants.AsyncRuntimeConfig, "true") cp.ExpectExitCode(0) @@ -106,13 +106,13 @@ func (suite *RevertIntegrationTestSuite) TestRevertTo() { defer ts.Close() namespace := "ActiveState-CLI/Revert" - ts.PrepareProject(namespace, "903bf49a-6719-47f0-ae70-450d69532ece") + ts.PrepareProject(namespace, "ca615135-ef95-4392-aff5-85b6c7132789") cp := ts.Spawn("config", "set", constants.AsyncRuntimeConfig, "true") cp.ExpectExitCode(0) // Revert the commit that added urllib3. - commitID := "1f4f4f7d-7883-400e-b2ad-a5803c018ecd" + commitID := "c44885ee-af0e-4f52-b8ef-63c56fe255c6" cp = ts.Spawn("revert", "--to", commitID) cp.Expect(fmt.Sprintf("Operating on project %s", namespace)) cp.Expect("You are about to revert to the following commit:") @@ -153,12 +153,12 @@ func (suite *RevertIntegrationTestSuite) TestJSON() { ts := e2e.New(suite.T(), false) defer ts.Close() - ts.PrepareProject("ActiveState-CLI/Revert", "903bf49a-6719-47f0-ae70-450d69532ece") + ts.PrepareProject("ActiveState-CLI/Revert", "ca615135-ef95-4392-aff5-85b6c7132789") cp := ts.Spawn("config", "set", constants.AsyncRuntimeConfig, "true") cp.ExpectExitCode(0) - cp = ts.Spawn("revert", "--to", "1f4f4f7d-7883-400e-b2ad-a5803c018ecd", "-o", "json") + cp = ts.Spawn("revert", "--to", "c44885ee-af0e-4f52-b8ef-63c56fe255c6", "-o", "json") cp.Expect(`{"current_commit_id":`, e2e.RuntimeSourcingTimeoutOpt) cp.ExpectExitCode(0) AssertValidJSON(suite.T(), cp) diff --git a/test/integration/use_int_test.go b/test/integration/use_int_test.go index 1f133600a4..8197507073 100644 --- a/test/integration/use_int_test.go +++ b/test/integration/use_int_test.go @@ -126,10 +126,10 @@ func (suite *UseIntegrationTestSuite) TestReset() { cfg, err := config.New() suite.NoError(err) + rcfile, err := subshell.New(cfg).RcFile() + suite.NoError(err) if runtime.GOOS != "windows" { - rcfile, err := subshell.New(cfg).RcFile() fileutils.FileExists(rcfile) - suite.NoError(err) suite.Contains(string(fileutils.ReadFileUnsafe(rcfile)), ts.Dirs.DefaultBin, "PATH does not have your project in it") } diff --git a/version.txt b/version.txt index ce3813278e..c325dfb59d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.48.1-RC1 +0.48.1-RC2