Skip to content

refactor: remove logger from activity, manifest, datastore, auth, and app delete/uninstall#364

Merged
mwbrooks merged 2 commits intomainfrom
mwbrooks-chopping-the-log-1
Mar 9, 2026
Merged

refactor: remove logger from activity, manifest, datastore, auth, and app delete/uninstall#364
mwbrooks merged 2 commits intomainfrom
mwbrooks-chopping-the-log-1

Conversation

@mwbrooks
Copy link
Member

@mwbrooks mwbrooks commented Mar 5, 2026

Changelog

  • N/A

Summary

This pull request is part 1 of removing internal/logger package and is focused on the straight-forward use-cases. It will be the largest, but simplest PR.

  • Removes internal/logger dependency from 5 command groups (activity, manifest, datastore, auth, and app delete/uninstall)
  • Migrate functions to return plain data types instead of *logger.LogEvent, with output printed directly by callers

Motivation

The internal/logger package implements an event-driven pub-sub pattern where internal/pkg/ emits named events through a logger and cmd/ subscribes to those events with callbacks that print output. This indirection makes control flow harder to follow and has already been abandoned in newer commands (e.g. cmd/datastore/count.go) which return plain data and print directly.

Test Steps

The ambitious can double-check the output against their production slack installation.

# Setup
$ lack create my-app -t https://github.com/slack-samples/deno-starter-template
$ cd my-app/

# TEST: auth list
$ lack auth list
# → Confirm expected output

# TEST: manifest validate
$ lack manifest validate
# → Confirm expected output (valid manifest)

# Deploy
$ lack deploy

# TEST: manifest validate (again, this time it will show warnings)
$ lack manifest validate
# → Confirm expected output (shows warnings if on an enterprise)

# TEST: activity
$  lack activity -t
# → Confirm expected output
# → Ambitious can execute a trigger to display more output

# TEST: datastore put 
$ lack datastore put --datastore SampleObjects '{"item": {"object_id": "42", "original_msg": "Original message", "updated_msg": "Updated message"}}'
# → Confirm expected output

# TEST: datastore bulk-put
$ lack datastore bulk-put --datastore SampleObjects '{"items": [{"object_id": "12", "original_msg": "Original message", "updated_msg": "Updated message"}, {"object_id": "24", "original_msg": "Original message", "updated_msg": "Updated message"}]}'
# → Confirm expected output

# TEST: datastore get
$ lack datastore get --datastore SampleObjects '{"id": "42"}'
# → Confirm expected output

# TEST: datastore bulk-get
$ lack datastore bulk-get --datastore SampleObjects '{"ids": ["12", "42"]}'
# → Confirm expected output

# TEST: datastore query
$ lack datastore query --datastore SampleObjects '{"limit": 8}' --output json
# → Confirm expected output (3 results)

# TEST: datastore update
$ lack datastore update --datastore SampleObjects '{"item": {"object_id": "42", "original_msg": "Modified original message", "updated_msg": "Modified updated message"}}'
# → Confirm expected output

# TEST: datastore delete
$ lack datastore delete --datastore SampleObjects '{"id": "12"}'
$ lack datastore query --datastore SampleObjects '{"limit": 8}' --output json
# → Confirm expected output (2 results)

# TEST: datastore bulk-delete
$ lack datastore bulk-delete --datastore SampleObjects '{"ids": ["24", "42"]}'
$ lack datastore query --datastore SampleObjects '{"limit": 8}' --output json
# → Confirm expected output (no results)

# TEST: app uninstall
$ lack uninstall
# → Confirm expected output

# TEST: app delete
$ lack delete
# → Confirm expected output

# Cleanup
$ cd ..
$ rm -rf my-app/

Requirements

@mwbrooks mwbrooks added this to the Next Release milestone Mar 5, 2026
@mwbrooks mwbrooks self-assigned this Mar 5, 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 5, 2026
@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 71.29630% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.09%. Comparing base (2a4bdaa) to head (f2f1841).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/pkg/apps/uninstall.go 0.00% 7 Missing ⚠️
cmd/manifest/validate.go 57.14% 5 Missing and 1 partial ⚠️
internal/pkg/apps/delete.go 50.00% 4 Missing ⚠️
internal/pkg/manifest/validate.go 57.14% 3 Missing ⚠️
cmd/platform/activity.go 0.00% 0 Missing and 1 partial ⚠️
internal/pkg/datastore/bulk_delete.go 66.66% 1 Missing ⚠️
internal/pkg/datastore/bulk_get.go 66.66% 1 Missing ⚠️
internal/pkg/datastore/bulk_put.go 66.66% 1 Missing ⚠️
internal/pkg/datastore/delete.go 66.66% 1 Missing ⚠️
internal/pkg/datastore/get.go 66.66% 1 Missing ⚠️
... and 5 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #364      +/-   ##
==========================================
- Coverage   65.14%   65.09%   -0.06%     
==========================================
  Files         216      216              
  Lines       18237    18082     -155     
==========================================
- Hits        11881    11770     -111     
+ Misses       5259     5222      -37     
+ Partials     1097     1090       -7     

☔ 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.

Leaving a few comments for the patience reviewers!

Comment on lines -102 to -125
// Set up event logger and execute the command
log := newDeleteLogger(clients, cmd, team)
log.Data["appID"] = selection.App.AppID
env, err := apps.Delete(ctx, clients, log, team, selection.App, selection.Auth)

return env, err
}
// Execute the command
env, teamName, err := apps.Delete(ctx, clients, team, selection.App, selection.Auth)
if err != nil {
return env, err
}
printDeleteApp(ctx, clients, selection.App.AppID, teamName)

// newDeleteLogger creates a logger instance to receive event notifications
func newDeleteLogger(clients *shared.ClientFactory, cmd *cobra.Command, envName string) *logger.Logger {
ctx := cmd.Context()
return logger.New(
// OnEvent
func(event *logger.LogEvent) {
appID := event.DataToString("appID")
teamName := event.DataToString("teamName")
switch event.Name {
case "on_apps_delete_app_success":
printDeleteApp(ctx, clients, appID, teamName)
default:
// Ignore the event
}
},
)
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 good example of a typical change.

Copy link
Member

Choose a reason for hiding this comment

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

🌟 praise: It's taken me a while to grasp this logging pattern. Thanks so much for making it more simple and consistent!


logger := newValidateLogger(clients, cmd)
log, warn, err := manifestValidateFunc(ctx, clients, logger, selection.App, token)
isValid, warn, err := manifestValidateFunc(ctx, clients, selection.App, token)
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: We now return isValid instead of log

Copy link
Member

Choose a reason for hiding this comment

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

💰 praise: I like how this makes later logic more obvious!

return types.App{}, "", slackerror.Wrap(err, slackerror.ErrAppRemove)
}

// Is this needed anymore?
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 caller may not have access to the team name and only the team domain or team ID.

Copy link
Member

Choose a reason for hiding this comment

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

🔏 thought: We should perhaps keep revisiting how selections are kept throughout a command! I understand the app might not exist after deletion but we should be confident in having the selection details kept!

🗣️ ramble(non-blocking): I'm most curious if teamName can be removed from the return arguments.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yea, I agree, I'd love to revisit how selections are kept throughout the command. Perhaps slackcontext is our answer?

Copy link
Member Author

Choose a reason for hiding this comment

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

I may be overlooking something, but we need the teamName for output purposes but the caller only has the team domain or team ID from the selection. We could move the output into this internal/ package, but I'd rather not do that in this PR. I'm trying to shuffle as little around as possible.

@mwbrooks mwbrooks marked this pull request as ready for review March 6, 2026 21:40
@mwbrooks mwbrooks requested a review from a team as a code owner March 6, 2026 21:40
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 Super big fan of these changes! Thanks for making the codebase more simple for upcoming efforts 👾 ✨

I left comments and praise with nothing blocking this from merging. The inlined outputs make API calls much simple to reason about for me 🧠 🙏

Comment on lines +94 to +95
_ = printBulkDeleteResult(clients, cmd, result)
printDatastoreBulkDeleteSuccess(cmd)
Copy link
Member

Choose a reason for hiding this comment

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

🌚 question(non-blocking): Do you think outputs will be joined in later changes? No rush at all, but this still seems indirect to me!

Copy link
Member Author

Choose a reason for hiding this comment

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

I definitely think we should take a step back and re-consider our outputs. We have outputs mixed between cmd/ and internal/pkg. My ideal world (right now) is that we 🪓 axe internal/pkg and move it all into cmd/. It'll make each command longer but keep it as "single file" and remove the questions of where things should go (cmd vs internal/pkg).

Comment on lines -102 to -125
// Set up event logger and execute the command
log := newDeleteLogger(clients, cmd, team)
log.Data["appID"] = selection.App.AppID
env, err := apps.Delete(ctx, clients, log, team, selection.App, selection.Auth)

return env, err
}
// Execute the command
env, teamName, err := apps.Delete(ctx, clients, team, selection.App, selection.Auth)
if err != nil {
return env, err
}
printDeleteApp(ctx, clients, selection.App.AppID, teamName)

// newDeleteLogger creates a logger instance to receive event notifications
func newDeleteLogger(clients *shared.ClientFactory, cmd *cobra.Command, envName string) *logger.Logger {
ctx := cmd.Context()
return logger.New(
// OnEvent
func(event *logger.LogEvent) {
appID := event.DataToString("appID")
teamName := event.DataToString("teamName")
switch event.Name {
case "on_apps_delete_app_success":
printDeleteApp(ctx, clients, appID, teamName)
default:
// Ignore the event
}
},
)
Copy link
Member

Choose a reason for hiding this comment

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

🌟 praise: It's taken me a while to grasp this logging pattern. Thanks so much for making it more simple and consistent!


logger := newValidateLogger(clients, cmd)
log, warn, err := manifestValidateFunc(ctx, clients, logger, selection.App, token)
isValid, warn, err := manifestValidateFunc(ctx, clients, selection.App, token)
Copy link
Member

Choose a reason for hiding this comment

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

💰 praise: I like how this makes later logic more obvious!

return types.App{}, "", slackerror.Wrap(err, slackerror.ErrAppRemove)
}

// Is this needed anymore?
Copy link
Member

Choose a reason for hiding this comment

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

🔏 thought: We should perhaps keep revisiting how selections are kept throughout a command! I understand the app might not exist after deletion but we should be confident in having the selection details kept!

🗣️ ramble(non-blocking): I'm most curious if teamName can be removed from the return arguments.

@mwbrooks
Copy link
Member Author

mwbrooks commented Mar 9, 2026

@zimeg Thanks for the review! 🙇🏻 It's a gnarly PR and I appreciate that you've taken the time to really look it over and think about the changes.

Your questions have a lot of weight and value. My hope is that by removing the package logger we can begin to think about where output should live and the relationship between cmd/ and internal/pkg.

For this PR, I'd feel most comfortable keeping it scoped to surgically removing package logger without moving logic around too much. While doing the work, I found it very easy to run into output formatting issues. So, I made an effort to keep the surfaces touch very precise.

It'll feel good to merge these PRs and give them a few days to bake 🍞 before our next release!

@mwbrooks mwbrooks merged commit 008e166 into main Mar 9, 2026
7 checks passed
@mwbrooks mwbrooks deleted the mwbrooks-chopping-the-log-1 branch March 9, 2026 23:18
@zimeg
Copy link
Member

zimeg commented Mar 9, 2026

@mwbrooks Super appreciate the responses too! I realize you might be thinking the same things while knowing how to scope a change ✨ 🔭

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.

2 participants