Skip to content

Commit 42782a3

Browse files
srtaalejClaude
andcommitted
Merge branch 'main' into ale-fetch-remote-manifest
Resolve conflicts by integrating main's stricter --app/--environment validation with the remote manifest fetch feature. Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
2 parents 6d6749a + a11d022 commit 42782a3

13 files changed

Lines changed: 514 additions & 370 deletions

File tree

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ jobs:
109109
default: "dev-build"
110110
docker: # run the steps with Docker
111111
# CircleCI Go images available at: https://hub.docker.com/r/circleci/golang/
112-
- image: cimg/go:1.26.3
112+
- image: cimg/go:1.26.4
113113
steps: # steps that comprise the `build` job
114114
- checkout # check out source code to working directory
115115
- restore_cache: # restores saved cache if no changes are detected since last run

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Set up Go
2121
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
2222
with:
23-
go-version: "1.26.3"
23+
go-version: "1.26.4"
2424
- name: Lint
2525
run: go tool golangci-lint run --timeout=5m
2626
- name: Unit Tests
@@ -49,7 +49,7 @@ jobs:
4949
- name: Set up Go
5050
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
5151
with:
52-
go-version: "1.26.3"
52+
go-version: "1.26.4"
5353
- name: Report health score
5454
uses: slackapi/slack-health-score@d58a419f15cdaff97e9aa7f09f95772830ab66f7 # v0.1.1
5555
with:

cmd/docgen/docgen.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func runDocGenCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, arg
108108
return slackerror.New(slackerror.ErrDocumentationGenerationFailed).WithRootCause(err)
109109
}
110110

111-
// Generate errors reference
111+
// Generate errors reference sorted alphabetically by error code
112112
file, err := clients.Fs.Create(filepath.Join(docsDirPath, "errors.md"))
113113
if err != nil {
114114
return err
@@ -118,7 +118,14 @@ func runDocGenCommandFunc(clients *shared.ClientFactory, cmd *cobra.Command, arg
118118
if err != nil {
119119
return err
120120
}
121-
err = tmpl.Execute(file, slackerror.ErrorCodeMap)
121+
errors := make([]slackerror.Error, 0, len(slackerror.ErrorCodeMap))
122+
for _, e := range slackerror.ErrorCodeMap {
123+
errors = append(errors, e)
124+
}
125+
slices.SortFunc(errors, func(a, b slackerror.Error) int {
126+
return strings.Compare(a.Code, b.Code)
127+
})
128+
err = tmpl.Execute(file, errors)
122129
if err != nil {
123130
return err
124131
}

cmd/docgen/errors.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ones, as well as a list of the errors the Slack CLI may raise, what they mean,
66
and some ways to remediate them.
77

88
## Slack CLI errors list
9-
{{range $key, $err := . }}
9+
{{range $err := . }}
1010
### {{ $err.Code }} {#{{ $err.Code }}}
1111
{{ if $err.Message }}
1212
**Message**: {{ $err.Message }}

cmd/externalauth/add_secret.go

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ func NewAddClientSecretCommand(clients *shared.ClientFactory) *cobra.Command {
3838
"Add the client secret for an external provider of a workflow app.",
3939
"",
4040
"This secret will be used when initiating the OAuth2 flow.",
41-
"",
42-
"This command is supported for apps deployed to Slack managed infrastructure but",
43-
"other apps can attempt to run the command with the --force flag.",
4441
}, "\n"),
4542
Example: style.ExampleCommandsf([]style.ExampleCommand{
4643
{
@@ -67,18 +64,10 @@ func NewAddClientSecretCommand(clients *shared.ClientFactory) *cobra.Command {
6764
return cmd
6865
}
6966

70-
// preRunAddClientSecretCommand determines if the command is supported for a
71-
// project and configures flags
72-
func preRunAddClientSecretCommand(ctx context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error {
67+
// preRunAddClientSecretCommand configures flags and validates the project directory
68+
func preRunAddClientSecretCommand(_ context.Context, clients *shared.ClientFactory, cmd *cobra.Command) error {
7369
clients.Config.SetFlags(cmd)
74-
err := cmdutil.IsValidProjectDirectory(clients)
75-
if err != nil {
76-
return err
77-
}
78-
if clients.Config.ForceFlag {
79-
return nil
80-
}
81-
return cmdutil.IsSlackHostedProject(ctx, clients)
70+
return cmdutil.IsValidProjectDirectory(clients)
8271
}
8372

8473
// runAddClientSecretCommand adds a client secret to an authentication provider

cmd/externalauth/add_secret_test.go

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import (
1919
"errors"
2020
"testing"
2121

22-
"github.com/slackapi/slack-cli/internal/app"
23-
"github.com/slackapi/slack-cli/internal/config"
2422
"github.com/slackapi/slack-cli/internal/iostreams"
2523
"github.com/slackapi/slack-cli/internal/shared"
2624
"github.com/slackapi/slack-cli/internal/shared/types"
@@ -34,88 +32,22 @@ import (
3432

3533
func TestExternalAuthAddClientSecretCommandPreRun(t *testing.T) {
3634
tests := map[string]struct {
37-
mockFlagForce bool
38-
mockManifestResponse types.SlackYaml
39-
mockManifestError error
40-
mockManifestSource config.ManifestSource
4135
mockWorkingDirectory string
4236
expectedError error
4337
}{
44-
"continues if the application is hosted on slack": {
45-
mockManifestResponse: types.SlackYaml{
46-
AppManifest: types.AppManifest{
47-
Settings: &types.AppSettings{
48-
FunctionRuntime: types.SlackHosted,
49-
},
50-
},
51-
},
52-
mockManifestError: nil,
38+
"continues if the command is run in a valid project directory": {
5339
mockWorkingDirectory: "/slack/path/to/project",
5440
expectedError: nil,
5541
},
56-
"errors if the application is not hosted on slack": {
57-
mockManifestResponse: types.SlackYaml{
58-
AppManifest: types.AppManifest{
59-
Settings: &types.AppSettings{
60-
FunctionRuntime: types.Remote,
61-
},
62-
},
63-
},
64-
mockManifestError: nil,
65-
mockManifestSource: config.ManifestSourceLocal,
66-
mockWorkingDirectory: "/slack/path/to/project",
67-
expectedError: slackerror.New(slackerror.ErrAppNotHosted),
68-
},
69-
"continues if the force flag is used in a project": {
70-
mockFlagForce: true,
71-
mockWorkingDirectory: "/slack/path/to/project",
72-
expectedError: nil,
73-
},
74-
"errors if the project manifest cannot be retrieved": {
75-
mockManifestResponse: types.SlackYaml{},
76-
mockManifestError: slackerror.New(slackerror.ErrSDKHookInvocationFailed),
77-
mockManifestSource: config.ManifestSourceLocal,
78-
mockWorkingDirectory: "/slack/path/to/project",
79-
expectedError: slackerror.New(slackerror.ErrSDKHookInvocationFailed),
80-
},
8142
"errors if the command is not run in a project": {
82-
mockManifestResponse: types.SlackYaml{},
83-
mockManifestError: slackerror.New(slackerror.ErrSDKHookNotFound),
84-
mockManifestSource: config.ManifestSourceLocal,
8543
mockWorkingDirectory: "",
8644
expectedError: slackerror.New(slackerror.ErrInvalidAppDirectory),
8745
},
88-
"errors if the manifest source is set to remote": {
89-
mockManifestSource: config.ManifestSourceRemote,
90-
mockWorkingDirectory: "/slack/path/to/project",
91-
expectedError: slackerror.New(slackerror.ErrAppNotHosted),
92-
},
9346
}
9447
for name, tc := range tests {
9548
t.Run(name, func(t *testing.T) {
9649
clientsMock := shared.NewClientsMock()
97-
manifestMock := &app.ManifestMockObject{}
98-
manifestMock.On(
99-
"GetManifestLocal",
100-
mock.Anything,
101-
mock.Anything,
102-
mock.Anything,
103-
).Return(
104-
tc.mockManifestResponse,
105-
tc.mockManifestError,
106-
)
107-
clientsMock.AppClient.Manifest = manifestMock
108-
projectConfigMock := config.NewProjectConfigMock()
109-
projectConfigMock.On(
110-
"GetManifestSource",
111-
mock.Anything,
112-
).Return(
113-
tc.mockManifestSource,
114-
nil,
115-
)
116-
clientsMock.Config.ProjectConfig = projectConfigMock
11750
clients := shared.NewClientFactory(clientsMock.MockClientFactory(), func(cf *shared.ClientFactory) {
118-
cf.Config.ForceFlag = tc.mockFlagForce
11951
cf.SDKConfig.WorkingDirectory = tc.mockWorkingDirectory
12052
})
12153
cmd := NewAddClientSecretCommand(clients)

cmd/project/create.go

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ import (
3737
)
3838

3939
// Flags
40-
var createTemplateURLFlag string
41-
var createGitBranchFlag string
4240
var createAppNameFlag string
41+
var createEnvironmentFlag string
42+
var createGitBranchFlag string
4343
var createListFlag bool
4444
var createSubdirFlag string
45-
var createEnvironmentFlag string
45+
var createTemplateURLFlag string
4646

4747
// Handle to client's create function used for testing
4848
// TODO - Find best practice, such as using an Interface and Struct to create a client
@@ -73,7 +73,7 @@ name your app 'agent' (not create an AI Agent), use the --name flag instead.`,
7373
{Command: "create my-project -t slack-samples/deno-hello-world", Meaning: "Start a new project from a specific template"},
7474
{Command: "create --name my-project", Meaning: "Create a project named 'my-project'"},
7575
{Command: "create my-project -t org/monorepo --subdir apps/my-app", Meaning: "Create from a subdirectory of a template"},
76-
{Command: "create my-project -t slack-samples/bolt-js-starter-template --app A0123456789", Meaning: "Create from template and link to an existing app"},
76+
{Command: "create my-project -t slack-samples/bolt-js-starter-template --app A0123456789 --environment local", Meaning: "Create from template and link to an existing app"},
7777
}),
7878
Args: cobra.MaximumNArgs(2),
7979
RunE: func(cmd *cobra.Command, args []string) error {
@@ -135,17 +135,29 @@ func runCreateCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []
135135
WithMessage("The --subdir flag requires the --template flag")
136136
}
137137

138+
// --app must be an app ID when used with create
139+
appFlagProvided := clients.Config.AppFlag != ""
140+
if appFlagProvided && !types.IsAppID(clients.Config.AppFlag) {
141+
return slackerror.New(slackerror.ErrInvalidAppFlag).
142+
WithMessage("The --app flag requires an app ID when used with create")
143+
}
144+
138145
// --app requires --template
139-
appFlagProvided := clients.Config.AppFlag != "" && types.IsAppID(clients.Config.AppFlag)
140146
if appFlagProvided && !templateFlagProvided {
141147
return slackerror.New(slackerror.ErrMismatchedFlags).
142148
WithMessage("The --app flag requires the --template flag when used with create")
143149
}
144150

145-
// --environment requires --app
146-
if cmd.Flags().Changed("environment") && !appFlagProvided {
147-
return slackerror.New(slackerror.ErrMismatchedFlags).
148-
WithMessage("The --environment flag requires the --app flag when used with create")
151+
// --environment requires --app and must be "local" or "deployed"
152+
if cmd.Flags().Changed("environment") {
153+
if !appFlagProvided {
154+
return slackerror.New(slackerror.ErrMismatchedFlags).
155+
WithMessage("The --environment flag requires the --app flag when used with create")
156+
}
157+
if !types.IsAppFlagEnvironment(createEnvironmentFlag) {
158+
return slackerror.New(slackerror.ErrMismatchedFlags).
159+
WithMessage("The --environment flag must be either 'local' or 'deployed'")
160+
}
149161
}
150162

151163
// Collect the template URL or select a starting template
@@ -209,14 +221,19 @@ func runCreateCommand(clients *shared.ClientFactory, cmd *cobra.Command, args []
209221
if err != nil {
210222
return slackerror.Wrap(err, slackerror.ErrAppDirectoryAccess)
211223
}
212-
originalDir, _ := clients.Os.Getwd()
224+
originalDir, err := clients.Os.Getwd()
225+
if err != nil {
226+
return slackerror.Wrap(err, slackerror.ErrAppDirectoryAccess)
227+
}
213228
if err := os.Chdir(absProjectPath); err != nil {
214229
return slackerror.Wrap(err, slackerror.ErrAppDirectoryAccess)
215230
}
231+
defer func() {
232+
_ = os.Chdir(originalDir)
233+
}()
216234

217235
linkedApp := &types.App{}
218236
auth, linkErr := app.LinkExistingApp(ctx, clients, linkedApp, false)
219-
_ = os.Chdir(originalDir)
220237
if linkErr != nil {
221238
return linkErr
222239
}

0 commit comments

Comments
 (0)