Skip to content

refactor: consolidate version access to slackcontext.Version(ctx)#431

Open
mwbrooks wants to merge 11 commits intomainfrom
mwbrooks-cli-version-refactor-1
Open

refactor: consolidate version access to slackcontext.Version(ctx)#431
mwbrooks wants to merge 11 commits intomainfrom
mwbrooks-cli-version-refactor-1

Conversation

@mwbrooks
Copy link
Member

@mwbrooks mwbrooks commented Mar 23, 2026

Changelog

  • N/A

Summary

This pull request consolidates version access to slackcontext.Version(ctx).

Currently, the version is accessed with version.Raw(), version.Get(), clients.config.Version, and slackcontext.Version(ctx). This is brittle, because it requires all version fields to be set to the same version. Additionally, the version value is passed as a parameter through some functions, which creates more risk of the incorrect version bring used.

  • Migrates version.Raw() callers to slackcontext.Version(ctx).
  • Standardizes on version.Raw(), previously it was a mix - most used .Raw(), but the recoveryFunc used .Get(). This could lead to difficulty associating log traces.
  • Removes clients.config.Version.
  • Replaces version string parameter with ctx parameter.
  • Simplifies mocks that required the version parameter.
  • Version now set once in main.go.

Open Questions

Test Steps

1. Version output

$ ./bin/slack --version
# → Confirm: the version string is displayed correctly (e.g. v0.x.x or a dev build SHA)

2. Version in debug output

$ ./bin/slack auth list --verbose --skip-update 2>&1 | grep -i version
# → Confirm: the CLI version appears in "Resolving logstash host"
# → Confirm: the CLI version appears in "FlushToLogstash"
# → Confirm no warnings about "version could not be found in context"

3.. User-Agent in API debug output

$ ./bin/slack auth login --verbose --skip-update 2>&1 | grep "User-Agent"
# - Confirm: the CLI version appears in "HTTP Request User-Agent"
# CTRL+C

4.. Log file version

$ ./bin/slack auth list
$ cat ~/.slack/logs/slack-debug-*.log | grep "Slack-CLI Version"
# → Confirm: last line in the log file contains the correct Slack-CLI Version value (not empty)
# → Example: "Slack-CLI Version: [v3.15.0]"

Requirements

The CLIVersion field and SetVersion functional option on ClientFactory
were a workaround for a circular dependency that no longer exists.
The API client reads version from context via slackcontext.Version(ctx),
making this indirection unnecessary. Replace with direct version.Raw()
calls.
Consumers now call version.Raw() directly instead of reading from
Config.Version, which was a redundant copy set in two places.
Remove re-added clients.Config.Version assignments that were
intentionally deleted in the Config.Version field refactor.
Replace direct version.Raw() calls with slackcontext.Version(ctx) across
all callers for improved testability via context-based dependency injection.

- slackcontext.Version(ctx) now falls back to version.Raw() when the
  context is missing the version, returning both the fallback value and
  an error so callers can log a warning
- ResolveLogstashHost no longer takes a cliVersion parameter; it reads
  the version from context internally
- Tracking tests use context-based version injection instead of mutating
  the global version.Version variable
@mwbrooks mwbrooks added this to the Next Release milestone Mar 23, 2026
@mwbrooks mwbrooks self-assigned this Mar 23, 2026
@mwbrooks mwbrooks added code health M-T: Test improvements and anything that improves code health semver:patch Use on pull requests to describe the release version increment labels Mar 23, 2026
@codecov
Copy link

codecov bot commented Mar 23, 2026

Codecov Report

❌ Patch coverage is 56.00000% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.23%. Comparing base (97fbfe8) to head (aec060b).

Files with missing lines Patch % Lines
internal/iostreams/logfile.go 0.00% 4 Missing ⚠️
main.go 0.00% 3 Missing ⚠️
internal/auth/auth.go 60.00% 1 Missing and 1 partial ⚠️
internal/tracking/tracking.go 50.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #431      +/-   ##
==========================================
- Coverage   70.27%   70.23%   -0.04%     
==========================================
  Files         220      220              
  Lines       18498    18506       +8     
==========================================
- Hits        12999    12998       -1     
- Misses       4324     4331       +7     
- Partials     1175     1177       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member Author

@mwbrooks mwbrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments for the wise reviewers!


clientsMock.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).
Return("api host")
clientsMock.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything, mock.Anything).
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: This is the bulk of the changes - the version parameter was removed from the ResolveLogstashHost, which simplifies our testing mocks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌟 praise: @mwbrooks Amazing use of the slackcontext values for gathering this now!

- ResolveLogstashHost(ctx, clients.Config.APIHostResolved, clients.Config.Version)
+ ResolveLogstashHost(ctx, clients.Config.APIHostResolved)

Comment on lines -299 to -300
// TODO(slackcontext) Consolidate storing CLI version to slackcontext
clients.Config.Version = version.Raw()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 Removing the TODO to consolidate the version to slackcontext.

Comment on lines +513 to +516
cliVersion, err := slackcontext.Version(ctx)
if err != nil {
c.io.PrintDebug(ctx, "Warning: %s", err.Error())
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: slackcontext.Version(ctx) will return an error when ctx doesn't include the version field. This could happen if the function is called with context.Background() or t.Context(), which doesn't have the Slack CLI context properties.

When an error happens, slackcontext.Version(ctx) falls back on version.Raw(), which is set by the compiler. So, it should be very reliable at returning the correct version even if the context was incorrectly passed into the function. However, still want to handle the error by printing an warning to the debug logs, so that it can be known and fixed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

falliing back on version.Raw() is nice!

TeamFlag string
TokenFlag string
NoColor bool
Version string
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🪓 shared.Config.Version

Comment on lines +174 to +176
// Version returns the CLI version associated with `ctx`. If the version is not
// found in the context, it falls back to version.Raw() and returns an error to
// signal that the context was not properly initialized.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: The important design decision is written in this comment.

setup: func(cfg *config.Config) {
cfg.Version = "v4.2.0"
ctxSetup: func(ctx context.Context) context.Context {
return slackcontext.SetVersion(ctx, "v4.2.0")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: This is a safer mock now :)

// Set context values
sessionID := uuid.New().String()
cliVersion := version.Get()
cliVersion := version.Raw()
Copy link
Member Author

@mwbrooks mwbrooks Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 discussion: This is an important decision that we should feel confident in.

Originally, the version used by slackcontext and log traces was version.Get() (always prefixes the 'v'). But, Logstash and API calls used version.Raw() (git tag, which has the 'v' by convention but not guaranteed).

This wasn't a problem because our git tags always have a prefixed 'v' (e.g. v3.15.0). However, if we created a git tag without the 'v' then version would be different in different places.

:two-cents: Consistency is more important than format. This PR does introduce the consistency, I hope, because we consolidate the version access through slackcontext.Version(ctx). w.r.t the version format, I went with version.Raw() so that we know our git tag is the source of truth. If someone creates a git tag with a different format, at least we know it all lines up. But, I'm open to either.

Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with using Raw() and i like the idea of having git tag as our source of truth! it means its less likely for our logstash, api calls, etc to have the wrong version. also if we did mistakenly make a git tag w/out the 'v', that version would be consistent everywhere else so it would be easier to correct

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 praise: Thanks for calling this out! I'd been stumped on what might be best too.

👾 thought: I was leaning toward using version.Get to guarantee that releases use the "v" prefix to avoid errors with the User-Agent format:

slack-cli/v3.4.5-example-2-ga7e71fe (os: darwin)

But agree that consistent formats is better! We might lean on CI to package releases to avoid nuance as well 🎁

🔭 question: Should we also remove version.Get in a follow up PR? It might be a chance to ask less from the regex package:

// Get the version and format it (e.g. `v1.0.0`)
func Get() string {
version := Version
if match, _ := regexp.MatchString(`^[^v]`, version); match {
version = "v" + version
}
return version
}


var ctx = context.Background()
ctx = slackcontext.SetSessionID(ctx, uuid.New().String())
ctx = slackcontext.SetVersion(ctx, version.Raw())
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: Cannot re-use the cliVersion above because this is the recovery() function.

@mwbrooks mwbrooks marked this pull request as ready for review March 24, 2026 16:47
@mwbrooks mwbrooks requested a review from a team as a code owner March 24, 2026 16:47
Copy link
Contributor

@srtaalej srtaalej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think consolidating into slackcontext.Version(ctx) was the right call! LGTM ⭐

Copy link
Member

@zimeg zimeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwbrooks Nice changes to these processes 📺 ✨

I left a handful of comments toward these changes without blockers! When the time is best please do merge 🚢

Most comments are around packages - I'm curious about a simple version package most.


clientsMock.Auth.On("ResolveAPIHost", mock.Anything, mock.Anything, mock.Anything).
Return("api host")
clientsMock.Auth.On("ResolveLogstashHost", mock.Anything, mock.Anything, mock.Anything).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌟 praise: @mwbrooks Amazing use of the slackcontext values for gathering this now!

- ResolveLogstashHost(ctx, clients.Config.APIHostResolved, clients.Config.Version)
+ ResolveLogstashHost(ctx, clients.Config.APIHostResolved)

if err != nil {
ioStream.PrintDebug(ctx, "Warning: %s", err.Error())
}
versionString, _ := strings.CutPrefix(cliVersion, "v")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
versionString, _ := strings.CutPrefix(cliVersion, "v")
versionString := strings.TrimPrefix(cliVersion, "v")

🔭 suggestion(non-blocking): The unhandled "found" value might be more confusing than a different method here? No blocker since that's unchanged from before but it might be a good time to improve this for later.

🔗 https://pkg.go.dev/strings#TrimPrefix

// Set context values
sessionID := uuid.New().String()
cliVersion := version.Get()
cliVersion := version.Raw()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 praise: Thanks for calling this out! I'd been stumped on what might be best too.

👾 thought: I was leaning toward using version.Get to guarantee that releases use the "v" prefix to avoid errors with the User-Agent format:

slack-cli/v3.4.5-example-2-ga7e71fe (os: darwin)

But agree that consistent formats is better! We might lean on CI to package releases to avoid nuance as well 🎁

🔭 question: Should we also remove version.Get in a follow up PR? It might be a chance to ask less from the regex package:

// Get the version and format it (e.g. `v1.0.0`)
func Get() string {
version := Version
if match, _ := regexp.MatchString(`^[^v]`, version); match {
version = "v" + version
}
return version
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

code health M-T: Test improvements and anything that improves code health semver:patch Use on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants