-
Notifications
You must be signed in to change notification settings - Fork 24
refactor: Add slackcontext package to DRY context management #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #7 +/- ##
==========================================
+ Coverage 62.78% 62.94% +0.16%
==========================================
Files 210 210
Lines 22053 22127 +74
==========================================
+ Hits 13846 13928 +82
+ Misses 7128 7115 -13
- Partials 1079 1084 +5 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| }, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| return runEnvListCommandFunc(clients) | ||
| return runEnvListCommandFunc(clients, cmd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While runEnvListCommandFunc(ctx, clients, cmd) would be a more appropriate format, the other env commands only pass cmd and fetch the context with cmd.Context().
This change is leaning on consistency and a smaller change footprint, since the PR is already quite large.
| cmd *cobra.Command, | ||
| ) error { | ||
| ctx := context.Background() | ||
| ctx := cmd.Context() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed getting the real context, so that the env list command can access the Slack CLI Version. Currently, all API requests for the env list command don't include the Version in the user-agent.
| // TODO(slackcontext) Consolidate storing SystemID to slackcontext | ||
| clients.Config.SystemID = systemID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be a larger refactor that can wait until we 🪓 axe storing state in clients.Config
| // TODO(slackcontext) Consolidate storing ProjectID to slackcontext | ||
| clients.Config.ProjectID = projectID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise, this can wait until we 🪓 axe storing state in clients.Config
| // TODO: ensure context is only used with setters and not with getters. After investigating, report: | ||
| // - internal/contextutil/contextutil.go has a `VersionFromContext` getter method which is used in various API methods when setting the user agent on HTTP requests, and when sending data up to logstash | ||
| // - internal/config/context.go has a variety of set and get methods related to app, token, team/enterprise/session/user/trace IDs, domains |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These files have been refactored to slackcontext and the comment is no longer relevant.
|
|
||
| cliVersion, err := slackcontext.Version(ctx) | ||
| if err != nil { | ||
| return nil, err | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These errors are bubbled up to the original caller. Previously, when version didn't exist, the API calls would be made with a "" empty string.
| type contextKey string | ||
|
|
||
| const CONTEXT_ENV contextKey = "env" | ||
| const CONTEXT_TOKEN contextKey = "token" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The remaining functions in this file don't belong in the slackcontext because they deal with run-time state - selected auth, team, app, etc. We may want to refactor this into a standardized selected app struct that can be passed around.
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func Test_SlackContext_OpenTracingSpan(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly disappointed that removing the untested contextutil.go and some of context.go didn't result in a higher test coverage increase. Oh well 🤷🏻
| // Create the parent context for the CLI execution | ||
| var ctx = context.Background() | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be the one and only time we call context.Background(). In a future PR, I'll scrub the code base for all references to it, because I'm sure there are still some.
| ctx = slackcontext.SetSessionID(ctx, uuid.New().String()) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a follow-up PR, I'd like to clean this up so that we can use the existing SessionID rather than generating a new one when there is an unrecoverable error.
zimeg
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mwbrooks What an incredible improvement to the codebase this is 🙏 ✨
All of these changes make a lot of sense to me and I like how you're thinking about the setting of context values in "root" a lot! This, and the error handling within, makes these callsites much more reliable IMO.
A comment below asks a question about possible bugs discovered, but I'm excited for these changes to merge too. All things are compiling and running well for me! 🚢 💨
| ctx := slackcontext.MockContext(t.Context()) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mwbrooks This is wonderful with the setup in root!
slack-cli/internal/slackcontext/slackcontext_mock.go
Lines 23 to 34 in aae77de
| const ( | |
| mockCLIVersion = "v1.2.3" | |
| ) | |
| // MockContext sets values in the context that are guaranteed to exist before | |
| // the Cobra root command is executed. | |
| func MockContext(ctx context.Context) context.Context { | |
| ctx = SetOpenTracingTraceID(ctx, uuid.New().String()) | |
| ctx = SetSessionID(ctx, uuid.New().String()) | |
| ctx = SetVersion(ctx, mockCLIVersion) | |
| return ctx | |
| } |
| }() | ||
| case <-ctx.Done(): | ||
| // No interrupt signal sent, command executed to completion | ||
| // FIXME - `.Done()` channel is triggered by `cancel()` and not a successfully completion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm super curious about this 👀
It's not super clear what the bug is but I'm not doubting that this might be causing problems... Were you noticing something strange during command completion?
| if span := opentracing.SpanFromContext(ctx); span != nil { | ||
| span.SetTag("project_id", clients.Config.ProjectID) | ||
| ctx = opentracing.ContextWithSpan(ctx, span) | ||
| } | ||
|
|
||
| ctx = slackcontext.SetProjectID(ctx, projectID) | ||
| rootCmd.SetContext(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👾 ✨
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to do this, because the rootCmd.ExecuteContext(ctx) will execute the command with our context. However, if someone called rootCmd.Context() before executing the Cobra command, they'll at least get the correct context.
| err := cmd.Execute() | ||
| err := cmd.ExecuteContext(ctx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL! Is this the same as Execute, but sets the ctx on the command?
Edit: Just saw the note in the PR description - this is neat! 🙏 📚
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You got it!
cmd.Execute()will use acontext.Background()(empty context)cmd.ExecuteContext(ctx)will usectx
Whenever someone called cmd.Context() they'll get whatever context has been set. We want to ensure that they always get our context.
|
@zimeg Thanks so much for lending your time to review this PR! 🙇🏻 Tedious and long, but I hope it positions us to manage our context in context of the context 😳 |
Summary
This pull request introduces the
package slackcontextto allow context to be managed in one place.Usage:
slackcontext.<Function>slackcontext.<SetFunction>.ExecuteContext(ctx)) socmd.Context()returns the correct contextThoughts:
ctxctxctxis immutable, any function that modifies it must return the newctxctxis updatedctxbeforerootCmd.ExecuteContext(ctx)Rule of thumb:
ctxdoesn't change afterrootCmd.ExecuteContext(ctx) is calledctxshould not contain required function args, such asfsorosso we'll need to think about where these should live long-termReviewers
Sorry about the massive PR. Most of the PR is updating tests to use
slackcontext.MockContext(ctx)instead ofcontext.Background(). This is because values such asVersionare required by the API Client.There should be no change to functionality.
Requirements