feat(cli): add chat share remove command#25842
Draft
DanielleMaywood wants to merge 8 commits into
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
🤖 This PR was written by Coder Agent on behalf of Danielle Maywood
Adds
coder exp chat share removefor revoking shared user or group access from chats.This builds on the chat share helpers from the previous PR, rejects role syntax for removals, maps removed actors to the chat deleted role, updates the ACL, and prints the resulting ACL.
Implementation plan
Chat Share CLI Implementation Plan
Goal: Introduce chat sharing CLI support as a three-PR stack:
coder exp chat share add, thenremove, thenstatus.Architecture: Extend the existing experimental chat CLI in
cli/exp_chat.gowith asharesubgroup that usescodersdk.NewExperimentalClient(client)to call the existing chat ACL API. The stack is additive: PR 1 creates shared parsing, lookup, formatting helpers plusadd; PR 2 addsremoveusing the same helpers; PR 3 addsstatus. Each PR is independently testable and targets the previous branch in the stack.Tech Stack: Go,
github.com/coder/serpentfor CLI commands,cli/cliuifor table and JSON formatting,codersdk.ExperimentalClientchat ACL methods,coderdtestplusdbgen.Chatfor CLI integration tests,make test RUN=...,make fmt, andmake lint.Stack and branch strategy
Use three feature branches and three draft PRs:
main: introducecoder exp chat share add.coder exp chat share remove.coder exp chat share status.Merge order after review:
main.Before each commit or push, verify the current branch and remote target. Do not push directly to
main. Use explicit branch names, for example:When opening draft PRs, set the base branch explicitly:
Include the required Coder Agent disclosure in PR bodies.
Command design
The command namespace is under the existing experimental chat command:
addacceptsname:roleand defaults an omitted role toread, so--user aliceis equivalent to--user alice:read. This preserves future role extensibility while keeping the current single-role UX convenient.removeaccepts names without roles and rejectsname:role, because removal maps tocodersdk.ChatRoleDeletedand roles on removal are ambiguous.statusprints the current chat ACL without changing it.All three commands print the current ACL as table output by default. The formatter must also support JSON through
cliui.JSONFormat(), matching workspace sharing.File map
Files to modify:
cli/exp_chat.gor.chatShareCommand()inchatCommand().Children.chatShareCommand,chatShareAddCommand,chatShareRemoveCommand, andchatShareStatusCommandacross the stack.cli/exp_chat_test.goNo SDK, API, database, or generated files should be needed. The API already exists in
codersdk/chats.goandcoderd/exp_chats_acl.go.Shared implementation details
Add these helpers in
cli/exp_chat.go, near the existing chat helpers or below the command definitions:Expected helper behavior:
parseChatShareIDparses UUIDs and returnsinvalid chat ID %q: %won failure.parseChatShareActorRoleparsesnameandname:role. It returns[2]string{name, role}with an empty role when omitted. It rejects empty names, empty roles after a colon, and strings with more than one colon.parseChatShareActorparses removal actors. It rejects any colon with an error likeinvalid user format %q: roles are only accepted by chat share addfrom the calling command.stringToChatRoleaccepts onlyreadand deleted role"". For user-entered add roles, only call it after defaulting empty role toread, so""is not accepted as explicit user input for add.fetchChatUsersAndGroupsmirrorsfetchUsersAndGroupsincli/sharing.go, but returnscodersdk.ChatRolemaps. Resolve users throughclient.OrganizationMembers(ctx, orgID)and groups throughclient.Groups(ctx, codersdk.GroupArguments{Organization: orgID.String()}).chatACLToTableusescliui.NewOutputFormatter(cliui.TableFormat([]chatShareRow{}, []string{"User", "Group", "Role"}), cliui.JSONFormat()). Output one row per non-deleted user and one row per non-deleted group. Do not expand group members.Use the chat's organization for lookup.
GetChat(ctx, chatID)returns acodersdk.Chat; usechat.OrganizationIDwhen callingfetchChatUsersAndGroups.PR 1: Introduce
coder exp chat share addTask 1: Add failing tests for
chat share addFiles:
Test:
cli/exp_chat_test.goStep 1: Add test imports.
Extend imports in
cli/exp_chat_test.goto include the packages required by chat ACL integration tests:Keep existing imports that are still used and let
gofmtsort them.TestExpChatShareAdd.Create a test with subtests:
Add these additional subtests in the same function:
ShareWithUserDefaultReadRole: call--user <username>and assert the persisted role isread.ShareWithMultipleUsers: callfmt.Sprintf("--user=%s:read,%s:read", user1.Username, user2.Username)and assert both users are in the ACL.RejectsUnknownRole: use--user alice:writewith a valid chat and assert the error containsinvalid role "write".RequiresActor: invokeexp chat share add <chat-id>without--useror--groupand assert the error containsat least one user or group must be provided.RejectsInvalidChatID: invokeexp chat share add not-a-uuid --user alice:readand assert the error containsinvalid chat ID.Do not add group tests in PR 1 unless the initial user tests are passing quickly. If group tests are added, create a group through the same helper pattern used in
cli/sharing_test.goand assert one group row is printed.make test RUN=TestExpChatShareAddExpected: failure mentions the missing
shareoraddcommand.Task 2: Implement
chat share addFiles:
Modify:
cli/exp_chat.goStep 1: Add required imports.
Add imports used by the new helpers:
Keep existing imports and run
gofmtlater.sharesubgroup.Update
chatCommand().Childrenfrom:to:
chatShareCommandwith onlyaddin PR 1.chatShareAddCommand.Implement this shape:
If
codersdk.Chatdoes not exposeOrganizationIDunder that exact name, inspectcodersdk/chats.goand use the actual field.Implement the helper signatures from the shared implementation section. Use
strings.Count(raw, ":")for actor parsing. Usecodersdk.UsernameValidRegex.MatchString(name)for basic actor-name validation, matching workspace sharing's validation style. For groups, use the same validation as users unless an existing group-name validation helper is available nearby.stringToChatRolemust be:In
fetchChatUsersAndGroups, when a parsed role is empty, replace it withstring(params.DefaultRole)before callingstringToChatRole.make test RUN=TestExpChatShareAddTask 3: Verify PR 1 broadly and commit
Files:
Modify:
cli/exp_chat.goTest:
cli/exp_chat_test.goStep 1: Run adjacent chat CLI tests.
Check branch first:
Commit message:
git add cli/exp_chat.go cli/exp_chat_test.go git commit -m 'feat(cli): add chat share add command'PR 2: Introduce
coder exp chat share removeStart from the PR 1 branch and create a stacked branch:
Task 4: Add failing tests for
chat share removeFiles:
Test:
cli/exp_chat_test.goStep 1: Add
TestExpChatShareRemove.Create a test with subtests:
Add these additional subtests:
RequiresActor: invokeexp chat share remove <chat-id>without--useror--groupand assert the error containsat least one user or group must be provided.RejectsRoleSyntax: invokeexp chat share remove <chat-id> --user alice:readand assert the error containsroles are only accepted by chat share add.RejectsInvalidChatID: invokeexp chat share remove not-a-uuid --user aliceand assert the error containsinvalid chat ID.Step 2: Run the new test and verify it fails because
removedoes not exist.make test RUN=TestExpChatShareRemoveTask 5: Implement
chat share removeFiles:
Modify:
cli/exp_chat.goStep 1: Register
removeinchatShareCommand.Update children to:
chatShareRemoveCommand.Implement the same structure as add with these differences:
Use:remove <chat-id> --user <user> --group <group>Short:Remove shared access for users or groups from a chat.parseChatShareActor, notparseChatShareActorRole.invalid user format %q: %worinvalid group format %q: %w.fetchChatUsersAndGroupswithDefaultRole: codersdk.ChatRoleDeleted.UpdateChatACLwith deleted-role maps.chatACLToTable.parseChatShareActorshould return an error whenstrings.Contains(raw, ":")is true. The error text should containroles are only accepted by chat share add.make test RUN=TestExpChatShareRemoveTask 6: Verify PR 2 broadly and commit
Files:
Modify:
cli/exp_chat.goTest:
cli/exp_chat_test.goStep 1: Run all chat share tests from PR 1 and PR 2.
git status --short --branch git branch --show-current git add cli/exp_chat.go cli/exp_chat_test.go git commit -m 'feat(cli): add chat share remove command'PR 3: Introduce
coder exp chat share statusStart from the PR 2 branch and create a stacked branch:
Task 7: Add failing tests for
chat share statusFiles:
Test:
cli/exp_chat_test.goStep 1: Add
TestExpChatShareStatus.Create a test with subtests:
Add these additional subtests:
RejectsInvalidChatID: invokeexp chat share status not-a-uuidand assertinvalid chat ID.RequiresChatID: invokeexp chat share statusand assert the command fails due to required argument.Step 2: Run the status test and verify it fails because
statusdoes not exist.make test RUN=TestExpChatShareStatusTask 8: Implement
chat share statusFiles:
Modify:
cli/exp_chat.goStep 1: Register
statusinchatShareCommand.Update children to:
chatShareStatusCommand.Implement this shape:
make test RUN=TestExpChatShareStatusTask 9: Verify PR 3 and full stack
Files:
Modify:
cli/exp_chat.goTest:
cli/exp_chat_test.goStep 1: Run all chat share tests.
git status --short --branch git branch --show-current git add cli/exp_chat.go cli/exp_chat_test.go git commit -m 'feat(cli): add chat share status command'PR descriptions
Each PR should be a draft PR and include the Coder Agent disclosure:
PR 1 summary:
PR 2 summary:
PR 3 summary:
Final verification checklist
Run from the top stacked branch after PR 3 implementation:
Expected result: all commands pass. If
make lintreports generated or unrelated repository issues, capture the exact output in the PR notes and do not hide it.