diff --git a/.vscode/settings.json b/.vscode/settings.json index 6810f17c..865e0e17 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,6 +20,7 @@ "slackdeps", "slackerror", "slackhq", + "slackmock", "slacktrace", "tabletests", "testutil" diff --git a/cmd/app/link.go b/cmd/app/link.go index 69dae262..ed183d77 100644 --- a/cmd/app/link.go +++ b/cmd/app/link.go @@ -202,7 +202,7 @@ func LinkExistingApp(ctx context.Context, clients *shared.ClientFactory, app *ty return nil } - if err := clients.Config.ProjectConfig.SetManifestSource(ctx, config.ManifestSourceRemote); err != nil { + if err := config.SetManifestSource(ctx, clients.Fs, clients.Os, config.ManifestSourceRemote); err != nil { // Log the error to the verbose output clients.IO.PrintDebug(ctx, "Error setting manifest source in project-level config: %s", err) // Display a user-friendly error with a workaround diff --git a/cmd/app/link_test.go b/cmd/app/link_test.go index fd77c289..0808d464 100644 --- a/cmd/app/link_test.go +++ b/cmd/app/link_test.go @@ -440,7 +440,7 @@ func Test_Apps_Link(t *testing.T) { cm.AddDefaultMocks() setupAppLinkCommandMocks(t, ctx, cm, cf) // Set manifest source to project to trigger confirmation prompt - if err := cm.Config.ProjectConfig.SetManifestSource(ctx, config.ManifestSourceLocal); err != nil { + if err := config.SetManifestSource(ctx, cm.Fs, cm.Os, config.ManifestSourceLocal); err != nil { require.FailNow(t, fmt.Sprintf("Failed to set the manifest source in the memory-based file system: %s", err)) } // Accept manifest source confirmation prompt @@ -509,7 +509,7 @@ func Test_Apps_Link(t *testing.T) { cm.AddDefaultMocks() setupAppLinkCommandMocks(t, ctx, cm, cf) // Set manifest source to project to trigger confirmation prompt - if err := cm.Config.ProjectConfig.SetManifestSource(ctx, config.ManifestSourceLocal); err != nil { + if err := config.SetManifestSource(ctx, cm.Fs, cm.Os, config.ManifestSourceLocal); err != nil { require.FailNow(t, fmt.Sprintf("Failed to set the manifest source in the memory-based file system: %s", err)) } // Decline manifest source confirmation prompt @@ -547,7 +547,7 @@ func Test_Apps_Link(t *testing.T) { cm.AddDefaultMocks() setupAppLinkCommandMocks(t, ctx, cm, cf) // Set manifest source to local - if err := cm.Config.ProjectConfig.SetManifestSource(ctx, config.ManifestSourceLocal); err != nil { + if err := config.SetManifestSource(ctx, cm.Fs, cm.Os, config.ManifestSourceLocal); err != nil { require.FailNow(t, fmt.Sprintf("Failed to set the manifest source in the memory-based file system: %s", err)) } // Mock manifest for Run-on-Slack app @@ -624,7 +624,7 @@ func Test_Apps_Link(t *testing.T) { cm.AddDefaultMocks() setupAppLinkCommandMocks(t, ctx, cm, cf) // Set manifest source to local - if err := cm.Config.ProjectConfig.SetManifestSource(ctx, config.ManifestSourceLocal); err != nil { + if err := config.SetManifestSource(ctx, cm.Fs, cm.Os, config.ManifestSourceLocal); err != nil { require.FailNow(t, fmt.Sprintf("Failed to set the manifest source in the memory-based file system: %s", err)) } // Mock manifest for Run-on-Slack app @@ -760,7 +760,7 @@ func setupAppLinkCommandMocks(t *testing.T, ctx context.Context, cm *shared.Clie require.FailNow(t, fmt.Sprintf("Failed to create the hooks file in the memory-based file system: %s", err)) } - if err := cm.Config.ProjectConfig.SetManifestSource(ctx, config.ManifestSourceRemote); err != nil { + if err := config.SetManifestSource(ctx, cm.Fs, cm.Os, config.ManifestSourceRemote); err != nil { require.FailNow(t, fmt.Sprintf("Failed to set the manifest source in the memory-based file system: %s", err)) } diff --git a/cmd/doctor/check.go b/cmd/doctor/check.go index 79af20a3..e3c54df9 100644 --- a/cmd/doctor/check.go +++ b/cmd/doctor/check.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "github.com/slackapi/slack-cli/internal/config" "github.com/slackapi/slack-cli/internal/deputil" "github.com/slackapi/slack-cli/internal/iostreams" "github.com/slackapi/slack-cli/internal/pkg/version" @@ -132,7 +133,7 @@ func checkProjectConfig(ctx context.Context, clients *shared.ClientFactory) Sect Label: "Configurations", Value: "your project's CLI settings", } - projectConfig, err := clients.Config.ProjectConfig.ReadProjectConfigFile(ctx) + projectConfig, err := config.ReadProjectConfigFile(ctx, clients.Fs, clients.Os) if err != nil { if slackerror.ToSlackError(err).Code != slackerror.ErrInvalidAppDirectory { section.Errors = append(section.Errors, *slackerror.ToSlackError(err)) diff --git a/cmd/doctor/check_test.go b/cmd/doctor/check_test.go index 033c33ed..f553df25 100644 --- a/cmd/doctor/check_test.go +++ b/cmd/doctor/check_test.go @@ -26,7 +26,9 @@ import ( "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" "github.com/slackapi/slack-cli/internal/slackcontext" + "github.com/slackapi/slack-cli/internal/slackdeps" "github.com/slackapi/slack-cli/internal/slackerror" + "github.com/slackapi/slack-cli/test/slackmock" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -144,10 +146,13 @@ func TestDoctorCheckProjectConfig(t *testing.T) { ctx := slackcontext.MockContext(t.Context()) clientsMock := shared.NewClientsMock() clientsMock.AddDefaultMocks() - pcm := &config.ProjectConfigMock{} - pcm.On("ReadProjectConfigFile", mock.Anything).Return(tt.projectConfig, nil) - clientsMock.Config.ProjectConfig = pcm clients := shared.NewClientFactory(clientsMock.MockClientFactory()) + + slackmock.CreateProject(t, ctx, clients.Fs, clients.Os, slackdeps.MockWorkingDirectory) + + _, err := config.WriteProjectConfigFile(ctx, clients.Fs, clients.Os, tt.projectConfig) + require.NoError(t, err) + expected := Section{ Label: "Configurations", Value: "your project's CLI settings", diff --git a/cmd/doctor/doctor_test.go b/cmd/doctor/doctor_test.go index 87887ca4..44d9f8ec 100644 --- a/cmd/doctor/doctor_test.go +++ b/cmd/doctor/doctor_test.go @@ -28,7 +28,9 @@ import ( "github.com/slackapi/slack-cli/internal/shared" "github.com/slackapi/slack-cli/internal/shared/types" "github.com/slackapi/slack-cli/internal/slackcontext" + "github.com/slackapi/slack-cli/internal/slackdeps" "github.com/slackapi/slack-cli/internal/slackerror" + "github.com/slackapi/slack-cli/test/slackmock" "github.com/slackapi/slack-cli/test/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -57,14 +59,16 @@ func TestDoctorCommand(t *testing.T) { clientsMock.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).Return("api.slack.com") clientsMock.API.On("ValidateSession", mock.Anything, mock.Anything).Return(api.AuthSession{}, nil) clientsMock.AddDefaultMocks() - pcm := &config.ProjectConfigMock{} - pcm.On("ReadProjectConfigFile", mock.Anything).Return(config.ProjectConfig{ + + slackmock.CreateProject(t, ctx, clientsMock.Fs, clientsMock.Os, slackdeps.MockWorkingDirectory) + _, err := config.WriteProjectConfigFile(ctx, clientsMock.Fs, clientsMock.Os, config.ProjectConfig{ ProjectID: expectedProjectID, Manifest: &config.ManifestConfig{ Source: config.ManifestSourceLocal.String(), }, - }, nil) - clientsMock.Config.ProjectConfig = pcm + }) + require.NoError(t, err) + scm := &config.SystemConfigMock{} scm.On("GetSurveyConfig", mock.Anything, mock.Anything).Return(config.SurveyConfig{}, nil) scm.On("SetSurveyConfig", mock.Anything, mock.Anything, mock.Anything).Return(nil) @@ -88,7 +92,7 @@ func TestDoctorCommand(t *testing.T) { cmd := NewDoctorCommand(clients) testutil.MockCmdIO(clients.IO, cmd) - err := cmd.ExecuteContext(ctx) + err = cmd.ExecuteContext(ctx) require.NoError(t, err) report, err := performChecks(ctx, clients) diff --git a/internal/app/app_client.go b/internal/app/app_client.go index 9fc8afbd..a0df3a36 100644 --- a/internal/app/app_client.go +++ b/internal/app/app_client.go @@ -251,7 +251,7 @@ func (ac *AppClient) CleanUp() { // if there are no tracked apps anymore and no config file, remove the .slack folder. // otherwise remove .slack/apps*.json files that contain no apps. - if ac.apps.IsEmpty() && !ac.config.ProjectConfig.ProjectConfigJSONFileExists(wd) { + if ac.apps.IsEmpty() && !config.ProjectConfigJSONFileExists(ac.fs, ac.os, wd) { var deployedAppsJSONFilePath = filepath.Join(wd, deployedAppsFilename) var dotSlackFolder = filepath.Dir(deployedAppsJSONFilePath) _ = ac.fs.RemoveAll(dotSlackFolder) diff --git a/internal/app/app_client_test.go b/internal/app/app_client_test.go index d910ccc1..1a55c7cd 100644 --- a/internal/app/app_client_test.go +++ b/internal/app/app_client_test.go @@ -637,7 +637,7 @@ func TestAppClient_CleanupSlackFolder(t *testing.T) { assert.True(t, ac.apps.IsEmpty(), "an unexpected app was found") require.NoError(t, err) - assert.False(t, ac.config.ProjectConfig.ProjectConfigJSONFileExists(wd), + assert.False(t, config.ProjectConfigJSONFileExists(ac.fs, ac.os, wd), "an unexpected config was found") dotSlackFolder := filepath.Dir(pathToAppsJSON) diff --git a/internal/config/experiments.go b/internal/config/experiments.go index 2bd24ab1..54d7e893 100644 --- a/internal/config/experiments.go +++ b/internal/config/experiments.go @@ -36,7 +36,7 @@ func (c *Config) LoadExperiments( } printDebug(ctx, fmt.Sprintf("active flag experiments: %s", experiments)) // Load from project config file - projectConfig, err := c.ProjectConfig.ReadProjectConfigFile(ctx) + projectConfig, err := ReadProjectConfigFile(ctx, c.fs, c.os) if err != nil && slackerror.ToSlackError(err).Code != slackerror.ErrInvalidAppDirectory { printDebug(ctx, fmt.Sprintf("failed to parse project-level config file: %s", err)) } else if err == nil { diff --git a/internal/config/project.go b/internal/config/project.go index a453fed1..b37546ca 100644 --- a/internal/config/project.go +++ b/internal/config/project.go @@ -52,12 +52,8 @@ type ProjectConfigManager interface { GetProjectID(ctx context.Context) (string, error) SetProjectID(ctx context.Context, projectID string) (string, error) GetManifestSource(ctx context.Context) (ManifestSource, error) - SetManifestSource(ctx context.Context, source ManifestSource) error GetSurveyConfig(ctx context.Context, name string) (SurveyConfig, error) SetSurveyConfig(ctx context.Context, name string, surveyConfig SurveyConfig) error - ReadProjectConfigFile(ctx context.Context) (ProjectConfig, error) - WriteProjectConfigFile(ctx context.Context, projectConfig ProjectConfig) (string, error) - ProjectConfigJSONFileExists(projectDirPath string) bool Cache() cache.Cacher } @@ -119,7 +115,7 @@ func (c *ProjectConfig) GetProjectID(ctx context.Context) (string, error) { span, ctx = opentracing.StartSpanFromContext(ctx, "GetProjectID") defer span.Finish() - var projectConfig, err = c.ReadProjectConfigFile(ctx) + var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os) if err != nil { return "", err } @@ -133,14 +129,14 @@ func (c *ProjectConfig) SetProjectID(ctx context.Context, projectID string) (str span, _ = opentracing.StartSpanFromContext(ctx, "SetProjectID") defer span.Finish() - var projectConfig, err = c.ReadProjectConfigFile(ctx) + var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os) if err != nil { return "", err } projectConfig.ProjectID = projectID - _, err = c.WriteProjectConfigFile(ctx, projectConfig) + _, err = WriteProjectConfigFile(ctx, c.fs, c.os, projectConfig) if err != nil { return "", err } @@ -154,7 +150,7 @@ func (c *ProjectConfig) GetManifestSource(ctx context.Context) (ManifestSource, span, ctx = opentracing.StartSpanFromContext(ctx, "GetManifestSource") defer span.Finish() - var projectConfig, err = c.ReadProjectConfigFile(ctx) + var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os) if err != nil { return "", err } @@ -175,10 +171,10 @@ func (c *ProjectConfig) GetManifestSource(ctx context.Context) (ManifestSource, } // SetManifestSource saves the manifest source preference for the project -func (c *ProjectConfig) SetManifestSource(ctx context.Context, source ManifestSource) error { +func SetManifestSource(ctx context.Context, fs afero.Fs, os types.Os, source ManifestSource) error { span, ctx := opentracing.StartSpanFromContext(ctx, "SetManifestSource") defer span.Finish() - projectConfig, err := c.ReadProjectConfigFile(ctx) + projectConfig, err := ReadProjectConfigFile(ctx, fs, os) if err != nil { return err } @@ -186,7 +182,7 @@ func (c *ProjectConfig) SetManifestSource(ctx context.Context, source ManifestSo projectConfig.Manifest = &ManifestConfig{} } projectConfig.Manifest.Source = source.String() - _, err = c.WriteProjectConfigFile(ctx, projectConfig) + _, err = WriteProjectConfigFile(ctx, fs, os, projectConfig) if err != nil { return err } @@ -199,7 +195,7 @@ func (c *ProjectConfig) GetSurveyConfig(ctx context.Context, name string) (Surve span, ctx = opentracing.StartSpanFromContext(ctx, "GetSurveyConfig") defer span.Finish() - var projectConfig, err = c.ReadProjectConfigFile(ctx) + var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os) if err != nil { return SurveyConfig{}, err } @@ -218,7 +214,7 @@ func (c *ProjectConfig) SetSurveyConfig(ctx context.Context, name string, survey span, ctx = opentracing.StartSpanFromContext(ctx, "SetSurveyConfig") defer span.Finish() - var projectConfig, err = c.ReadProjectConfigFile(ctx) + var projectConfig, err = ReadProjectConfigFile(ctx, c.fs, c.os) if err != nil { return err } @@ -228,7 +224,7 @@ func (c *ProjectConfig) SetSurveyConfig(ctx context.Context, name string, survey CompletedAt: surveyConfig.CompletedAt, } - _, err = c.WriteProjectConfigFile(ctx, projectConfig) + _, err = WriteProjectConfigFile(ctx, c.fs, c.os, projectConfig) if err != nil { return err } @@ -237,24 +233,24 @@ func (c *ProjectConfig) SetSurveyConfig(ctx context.Context, name string, survey } // ReadProjectConfigFile reads the project-level config.json file -func (c *ProjectConfig) ReadProjectConfigFile(ctx context.Context) (ProjectConfig, error) { +func ReadProjectConfigFile(ctx context.Context, fs afero.Fs, os types.Os) (ProjectConfig, error) { var span opentracing.Span span, _ = opentracing.StartSpanFromContext(ctx, "ReadProjectConfigFile") defer span.Finish() var projectConfig ProjectConfig - projectDirPath, err := GetProjectDirPath(c.fs, c.os) + projectDirPath, err := GetProjectDirPath(fs, os) if err != nil { return projectConfig, err } - if !c.ProjectConfigJSONFileExists(projectDirPath) { + if !ProjectConfigJSONFileExists(fs, os, projectDirPath) { return projectConfig, nil } var projectConfigFilePath = GetProjectConfigJSONFilePath(projectDirPath) - projectConfigFileBytes, err := afero.ReadFile(c.fs, projectConfigFilePath) + projectConfigFileBytes, err := afero.ReadFile(fs, projectConfigFilePath) if err != nil { return projectConfig, err } @@ -274,7 +270,7 @@ func (c *ProjectConfig) ReadProjectConfigFile(ctx context.Context) (ProjectConfi } // WriteProjectConfigFile writes the project-level config.json file -func (c *ProjectConfig) WriteProjectConfigFile(ctx context.Context, projectConfig ProjectConfig) (string, error) { +func WriteProjectConfigFile(ctx context.Context, fs afero.Fs, os types.Os, projectConfig ProjectConfig) (string, error) { var span opentracing.Span span, _ = opentracing.StartSpanFromContext(ctx, "WriteProjectConfigFile") defer span.Finish() @@ -284,13 +280,13 @@ func (c *ProjectConfig) WriteProjectConfigFile(ctx context.Context, projectConfi return "", err } - projectDirPath, err := GetProjectDirPath(c.fs, c.os) + projectDirPath, err := GetProjectDirPath(fs, os) if err != nil { return "", err } projectConfigFilePath := GetProjectConfigJSONFilePath(projectDirPath) - err = afero.WriteFile(c.fs, projectConfigFilePath, projectConfigBytes, 0600) + err = afero.WriteFile(fs, projectConfigFilePath, projectConfigBytes, 0644) if err != nil { return "", err } @@ -299,9 +295,9 @@ func (c *ProjectConfig) WriteProjectConfigFile(ctx context.Context, projectConfi } // ProjectConfigJSONFileExists returns true if the .slack/config.json file exists -func (c *ProjectConfig) ProjectConfigJSONFileExists(projectDirPath string) bool { +func ProjectConfigJSONFileExists(fs afero.Fs, os types.Os, projectDirPath string) bool { var projectConfigFilePath = GetProjectConfigJSONFilePath(projectDirPath) - _, err := c.fs.Stat(projectConfigFilePath) + _, err := fs.Stat(projectConfigFilePath) return !os.IsNotExist(err) } diff --git a/internal/config/project_mock.go b/internal/config/project_mock.go index 8037dbfc..3de65986 100644 --- a/internal/config/project_mock.go +++ b/internal/config/project_mock.go @@ -53,11 +53,6 @@ func (m *ProjectConfigMock) GetManifestSource(ctx context.Context) (ManifestSour return args.Get(0).(ManifestSource), args.Error(1) } -func (m *ProjectConfigMock) SetManifestSource(ctx context.Context, source ManifestSource) error { - args := m.Called(ctx, source) - return args.Error(0) -} - func (m *ProjectConfigMock) GetSurveyConfig(ctx context.Context, id string) (SurveyConfig, error) { args := m.Called(ctx, id) return args.Get(0).(SurveyConfig), args.Error(1) @@ -68,21 +63,6 @@ func (m *ProjectConfigMock) SetSurveyConfig(ctx context.Context, id string, surv return args.Error(0) } -func (m *ProjectConfigMock) ReadProjectConfigFile(ctx context.Context) (ProjectConfig, error) { - args := m.Called(ctx) - return args.Get(0).(ProjectConfig), args.Error(1) -} - -func (m *ProjectConfigMock) WriteProjectConfigFile(ctx context.Context, projectConfig ProjectConfig) (string, error) { - args := m.Called(ctx, projectConfig) - return args.String(0), args.Error(1) -} - -func (m *ProjectConfigMock) ProjectConfigJSONFileExists(projectDirPath string) bool { - args := m.Called(projectDirPath) - return args.Bool(0) -} - // Cache returns a persistent mock cache func (m *ProjectConfigMock) Cache() cache.Cacher { args := m.Called() diff --git a/internal/config/project_test.go b/internal/config/project_test.go index ab94c713..04770e9f 100644 --- a/internal/config/project_test.go +++ b/internal/config/project_test.go @@ -104,7 +104,7 @@ func Test_ProjectConfig_InitProjectID(t *testing.T) { // Set a project_id that should not be overwritten expectedProjectID := uuid.New().String() - _, err := projectConfig.WriteProjectConfigFile(ctx, ProjectConfig{ProjectID: expectedProjectID}) + _, err := WriteProjectConfigFile(ctx, fs, os, ProjectConfig{ProjectID: expectedProjectID}) require.NoError(t, err) projectID, err := projectConfig.InitProjectID(ctx, false) @@ -128,7 +128,7 @@ func Test_ProjectConfig_InitProjectID(t *testing.T) { // Set a project_id that should be overwritten expectedProjectID := uuid.New().String() - _, err := projectConfig.WriteProjectConfigFile(ctx, ProjectConfig{ProjectID: expectedProjectID}) + _, err := WriteProjectConfigFile(ctx, fs, os, ProjectConfig{ProjectID: expectedProjectID}) require.NoError(t, err) projectID, err := projectConfig.InitProjectID(ctx, true) @@ -171,7 +171,7 @@ func Test_ProjectConfig_GetProjectID(t *testing.T) { // Set a project_id that has whitespace padding const paddedProjectID = " abc-123 " - _, err := projectConfig.WriteProjectConfigFile(ctx, ProjectConfig{ProjectID: paddedProjectID}) + _, err := WriteProjectConfigFile(ctx, fs, os, ProjectConfig{ProjectID: paddedProjectID}) require.NoError(t, err) projectID, err := projectConfig.GetProjectID(ctx) @@ -213,7 +213,7 @@ func Test_ProjectConfig_SetProjectID(t *testing.T) { projectConfig := NewProjectConfig(fs, os) // Set a project_id that will be replaced later - _, err := projectConfig.WriteProjectConfigFile(ctx, ProjectConfig{ProjectID: uuid.New().String()}) + _, err := WriteProjectConfigFile(ctx, fs, os, ProjectConfig{ProjectID: uuid.New().String()}) require.NoError(t, err) var expectedProjectID = uuid.New().String() @@ -263,7 +263,7 @@ func Test_ProjectConfig_ManifestSource(t *testing.T) { initial, err := config.GetManifestSource(ctx) require.NoError(t, err) assert.Equal(t, tt.expectedManifestSourceDefault, initial) - err = config.SetManifestSource(ctx, tt.mockManifestSource) + err = SetManifestSource(ctx, fs, os, tt.mockManifestSource) require.NoError(t, err) actual, err := config.GetManifestSource(ctx) assert.Equal(t, tt.expectedError, err) @@ -282,8 +282,7 @@ func Test_ProjectConfig_ReadProjectConfigFile(t *testing.T) { os.AddDefaultMocks() // Do not add the project mocks - projectConfig := NewProjectConfig(fs, os) - projectConfigData, err := projectConfig.ReadProjectConfigFile(ctx) + projectConfigData, err := ReadProjectConfigFile(ctx, fs, os) require.Error(t, err) require.Empty(t, projectConfigData) }) @@ -303,8 +302,7 @@ func Test_ProjectConfig_ReadProjectConfigFile(t *testing.T) { _, err := fs.Stat(GetProjectConfigJSONFilePath(slackdeps.MockWorkingDirectory)) require.True(t, os.IsNotExist(err)) - projectConfig := NewProjectConfig(fs, os) - projectConfigFile, err := projectConfig.ReadProjectConfigFile(ctx) + projectConfigFile, err := ReadProjectConfigFile(ctx, fs, os) require.NoError(t, err) require.Empty(t, projectConfigFile) // Currently, the default is an empty config.json ("{}") but this may change in the future }) @@ -325,11 +323,10 @@ func Test_ProjectConfig_ReadProjectConfigFile(t *testing.T) { Surveys: map[string]SurveyConfig{}, } - projectConfig := NewProjectConfig(fs, os) - _, err := projectConfig.WriteProjectConfigFile(ctx, expectedProjectConfig) + _, err := WriteProjectConfigFile(ctx, fs, os, expectedProjectConfig) require.NoError(t, err) - projectConfigFile, err := projectConfig.ReadProjectConfigFile(ctx) + projectConfigFile, err := ReadProjectConfigFile(ctx, fs, os) require.NoError(t, err) require.Equal(t, expectedProjectConfig, projectConfigFile) }) @@ -341,7 +338,6 @@ func Test_ProjectConfig_ReadProjectConfigFile(t *testing.T) { os.AddDefaultMocks() addProjectMocks(t, fs) - projectConfig := NewProjectConfig(fs, os) projectDirPath, err := GetProjectDirPath(fs, os) require.NoError(t, err) @@ -351,7 +347,7 @@ func Test_ProjectConfig_ReadProjectConfigFile(t *testing.T) { err = afero.WriteFile(fs, projectConfigFilePath, []byte(expectedConfigFileData), 0600) require.NoError(t, err) - _, err = projectConfig.ReadProjectConfigFile(ctx) + _, err = ReadProjectConfigFile(ctx, fs, os) require.Error(t, err) assert.Equal(t, slackerror.ToSlackError(err).Code, slackerror.ErrUnableToParseJSON) assert.Equal(t, slackerror.ToSlackError(err).Message, "Failed to parse contents of project-level config file") @@ -372,8 +368,7 @@ func Test_ProjectConfig_WriteProjectConfigFile(t *testing.T) { ProjectID: uuid.New().String(), } - projectConfig := NewProjectConfig(fs, os) - projectConfigData, err := projectConfig.WriteProjectConfigFile(ctx, defaultProjectConfig) + projectConfigData, err := WriteProjectConfigFile(ctx, fs, os, defaultProjectConfig) require.Error(t, err) require.Empty(t, projectConfigData) }) @@ -395,12 +390,11 @@ func Test_ProjectConfig_WriteProjectConfigFile(t *testing.T) { } // Assert writing the config file - projectConfig := NewProjectConfig(fs, os) - _, err := projectConfig.WriteProjectConfigFile(ctx, expectedProjectConfig) + _, err := WriteProjectConfigFile(ctx, fs, os, expectedProjectConfig) require.NoError(t, err) // Assert reading the written file contents - actualProjectConfig, err := projectConfig.ReadProjectConfigFile(ctx) + actualProjectConfig, err := ReadProjectConfigFile(ctx, fs, os) require.NoError(t, err) // Assert the written file has the same content as the original @@ -423,8 +417,7 @@ func Test_ProjectConfig_ProjectConfigJSONFileExists(t *testing.T) { err := afero.WriteFile(fs, GetProjectConfigJSONFilePath(slackdeps.MockWorkingDirectory), []byte("{}\n"), 0600) require.NoError(t, err) - projectConfig := NewProjectConfig(fs, os) - exists := projectConfig.ProjectConfigJSONFileExists(slackdeps.MockWorkingDirectory) + exists := ProjectConfigJSONFileExists(fs, os, slackdeps.MockWorkingDirectory) require.True(t, exists) }) @@ -441,8 +434,7 @@ func Test_ProjectConfig_ProjectConfigJSONFileExists(t *testing.T) { // Remove .slack/config.json and ignore errors (errors when file does not exist) _ = fs.Remove(GetProjectConfigJSONFilePath(slackdeps.MockWorkingDirectory)) - projectConfig := NewProjectConfig(fs, os) - exists := projectConfig.ProjectConfigJSONFileExists(slackdeps.MockWorkingDirectory) + exists := ProjectConfigJSONFileExists(fs, os, slackdeps.MockWorkingDirectory) require.False(t, exists) }) } diff --git a/internal/pkg/create/create.go b/internal/pkg/create/create.go index bde5121d..ffb36dc2 100644 --- a/internal/pkg/create/create.go +++ b/internal/pkg/create/create.go @@ -476,7 +476,7 @@ func InstallProjectDependencies( } // Set "manifest.source" in .slack/config.json - if err := clients.Config.ProjectConfig.SetManifestSource(ctx, manifestSource); err != nil { + if err := config.SetManifestSource(ctx, clients.Fs, clients.Os, manifestSource); err != nil { clients.IO.PrintDebug(ctx, "Error setting manifest source in project-level config: %s", err) } else { configJSONFilename := config.ProjectConfigJSONFilename diff --git a/test/slackmock/slackmock.go b/test/slackmock/slackmock.go new file mode 100644 index 00000000..e924849f --- /dev/null +++ b/test/slackmock/slackmock.go @@ -0,0 +1,47 @@ +// Copyright 2022-2025 Salesforce, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// 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. + +package slackmock + +import ( + "context" + "path/filepath" + + "github.com/slackapi/slack-cli/internal/config" + "github.com/slackapi/slack-cli/internal/shared/types" + "github.com/spf13/afero" + "github.com/stretchr/testify/require" +) + +// createProject will mock a project's required directory and files. +// If there is an error, it will fail the test. +func CreateProject(t require.TestingT, ctx context.Context, fs afero.Fs, os types.Os, projectDirPath string) { + var err error + + // Create the directory: `path/to/project` + err = fs.Mkdir(projectDirPath, 0755) + require.NoError(t, err) + + // Create the project-level config directory: `path/to/project/.slack/` + err = fs.Mkdir(filepath.Join(projectDirPath, config.ProjectConfigDirName), 0755) + require.NoError(t, err) + + // Create the project-level config file: `path/to/project/.slack/config.json` + err = afero.WriteFile(fs, config.GetProjectConfigJSONFilePath(projectDirPath), []byte("{}\n"), 0644) + require.NoError(t, err) + + // Create the project-level hooks file: `path/to/project/.slack/hooks.json` + err = afero.WriteFile(fs, config.GetProjectHooksJSONFilePath(projectDirPath), []byte("{}\n"), 0644) + require.NoError(t, err) +}