Skip to content

feat(feed): add +sensitive shortcut for time-sensitive status#718

Closed
jinzemo wants to merge 10 commits intolarksuite:mainfrom
jinzemo:feat/im-feed-card-time-sensitive
Closed

feat(feed): add +sensitive shortcut for time-sensitive status#718
jinzemo wants to merge 10 commits intolarksuite:mainfrom
jinzemo:feat/im-feed-card-time-sensitive

Conversation

@jinzemo
Copy link
Copy Markdown

@jinzemo jinzemo commented Apr 29, 2026

Summary

Add a new feed domain with a single shortcut +sensitive that calls the Lark PATCH /im/v2/feed_cards/:feed_card_id API to set or unset the time-sensitive (即时提醒/置顶) status of a feed card for specified users in a group chat.

Changes

  • New shortcuts/feed/ package with +sensitive command
  • Validation: --enable/--disable mutual exclusion, oc_ prefix check for feed-card-id
  • Partial failure handling: warnings to stderr, exit 1 with structured error
  • Skill docs: skills/lark-feed/SKILL.md and references/lark-feed-sensitive.md
  • E2E tests: 4 scenarios (enable/disable/dry-run/validation)

Test Plan

  • Unit tests: 8/8 pass (validation + execute with httpmock)
  • E2E tests: 4/4 pass (sandbox)
  • Skill eval: 7/7 pass (sandbox)
  • Manual dry-run verification

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced feed +sensitive shortcut to manage time-sensitive status for feed cards in group chats. Supports per-user enable/disable operations, dry-run mode for previewing changes, and detailed error reporting.
  • Documentation

    • Added skill documentation with prerequisites and comprehensive command reference guides for feed card management.
  • Tests

    • Added unit and end-to-end tests validating command parameters, execution workflows, and error handling scenarios.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


maojinze.7 seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

This PR introduces a new CLI shortcut feed +sensitive that toggles feed card time-sensitive status for specified users. It includes the shortcut implementation with PATCH request handling, parameter validation, response parsing, comprehensive unit and end-to-end test coverage, and user documentation.

Changes

Cohort / File(s) Summary
Type Documentation
shortcuts/common/types.go
Updated Flag.Type inline documentation to include "string_slice" as an additional supported type string value.
Feed Shortcut Implementation
shortcuts/feed/feed_sensitive.go
Implements the feed +sensitive shortcut command. Validates --feed-card-id format (requires oc_ prefix), enforces mutual exclusivity of --enable/--disable, and requires non-empty --user-ids. Executes a PATCH request to /open-apis/im/v2/feed_cards/{feedCardID} with user_id_type query param. Parses failed_user_reasons from response, reports successes to stdout and failures to stderr, and returns appropriate exit errors for partial or complete failures.
Shortcut Registration
shortcuts/feed/shortcuts.go, shortcuts/register.go
Introduces Shortcuts() function to expose FeedSensitive shortcut and imports feed package into global registry during initialization, making feed shortcuts available alongside other service domains.
Unit Tests
shortcuts/feed/shortcuts_test.go, shortcuts/feed/feed_sensitive_test.go
Tests shortcut registration count and fields, validates parameter enforcement (--enable/--disable mutual exclusivity, oc_ prefix requirement, non-empty user IDs), and verifies API response parsing with HTTP mocks for success, partial failure, and total failure scenarios.
End-to-End Tests
tests_e2e/feed/2026_04_29_feed_sensitive_test.go
Adds workflows for enable/disable operations creating a group chat and user, verifies JSON response envelope integrity, validates dry-run output format, and tests validation error handling with non-zero exit codes.
Documentation
skills/lark-feed/SKILL.md, skills/lark-feed/references/lark-feed-sensitive.md
Provides skill documentation and command reference. Specifies prerequisites (shared auth/permissions, shortcut guide), required parameters (--feed-card-id, --user-ids), usage examples with various user ID formats, exit code semantics for success/failure scenarios, and constraints (group chat only, bot identity required, feed-card-id prefix requirement).

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as CLI Command
    participant Validator as Parameter Validator
    participant RequestBuilder as Request Builder
    participant API as Lark API
    participant Parser as Response Parser

    User->>CLI: feed +sensitive --feed-card-id oc_xxx --enable --user-ids id1,id2
    CLI->>Validator: Validate parameters
    Validator->>Validator: Check --enable/--disable mutuality
    Validator->>Validator: Verify oc_ prefix in feed-card-id
    Validator->>Validator: Ensure non-empty user-ids
    alt Validation Fails
        Validator-->>CLI: Error
        CLI-->>User: Exit with validation error
    else Validation Passes
        Validator-->>CLI: Valid params
        CLI->>RequestBuilder: Build PATCH request
        RequestBuilder-->>CLI: PATCH /im/v2/feed_cards/oc_xxx
        CLI->>API: Send PATCH with time_sensitive=true, user_ids
        API-->>CLI: JSON response {data, failed_user_reasons}
        CLI->>Parser: Parse response
        Parser->>Parser: Extract failed_user_reasons
        Parser->>Parser: Compute success count
        alt All Users Failed
            Parser-->>CLI: All failed error
            CLI-->>User: stderr: warnings, stdout: error message
        else Some Users Failed
            Parser-->>CLI: Partial failure error
            CLI-->>User: stderr: warnings, stdout: success message
        else All Users Succeeded
            Parser-->>CLI: Success
            CLI-->>User: stdout: success message
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

size/L, domain/ccm

Suggested reviewers

  • fangshuyu-768
  • hugang-lark

Poem

🐰 A feed card now knows when it's sensitive and true,
With +sensitive whispers and toggles brand new,
Bot identity guards it, oc_ prefixed with pride,
Lark group chats rejoice with this time-honored guide! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the primary change: adding a new +sensitive shortcut to the feed domain for managing time-sensitive status.
Description check ✅ Passed The PR description follows the template structure with Summary, Changes, and Test Plan sections all completed with concrete implementation details and test results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added the size/L Large or sensitive change across domains or core paths label Apr 29, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shortcuts/feed/feed_sensitive.go`:
- Around line 59-62: The current check only ensures userIDs has non-zero length
but allows blank or whitespace-only elements; after retrieving userIDs :=
runtime.StrSlice("user-ids"), iterate the slice, trim each entry using
strings.TrimSpace and reject if any trimmed value == "" (return
output.ErrValidation with a clear message like "--user-ids must not contain
empty values"); optionally replace the slice with the cleaned/trimmed values
(e.g., build a new slice of trimmed IDs) before further use so downstream code
receives normalized IDs.

In `@tests_e2e/feed/2026_04_29_feed_sensitive_test.go`:
- Around line 237-260: createChatForFeed currently leaves created chats behind;
add a best-effort cleanup by registering t.Cleanup in createChatForFeed to
remove the chat_id when the test finishes. After extracting chatID (in
createChatForFeed), call t.Cleanup(func(){ ... }) that attempts to delete the
chat using the available removal path (e.g. use clie2e.RunCmd with the
appropriate "im +chat-delete" args if supported, or call the API client used
elsewhere in tests), ensure deletion failures are non-fatal but logged (use
t.Log or t.Errorf), and remove the unused parentT handling; keep the cleanup
best-effort and tolerant of missing delete commands/errors.
- Around line 120-136: The dry-run test TestFeedSensitive_DryRunFlagBehavior
must not read real developer credentials; before calling clie2e.RunCmd, set
LARKSUITE_CLI_CONFIG_DIR, LARKSUITE_CLI_APP_ID, LARKSUITE_CLI_APP_SECRET, and
LARKSUITE_CLI_BRAND to fake values (either by adding them to the clie2e.Request
env/Env field if supported or by calling os.Setenv with defer restore) so the
subprocess is isolated; implement this inline in
TestFeedSensitive_DryRunFlagBehavior (or add a small helper used by this test
and other dry-run tests) and then call clie2e.RunCmd as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f9d8de14-589e-47c9-a5f5-ee09561ab4f9

📥 Commits

Reviewing files that changed from the base of the PR and between 2eb9fae and 715b2da.

📒 Files selected for processing (9)
  • shortcuts/common/types.go
  • shortcuts/feed/feed_sensitive.go
  • shortcuts/feed/feed_sensitive_test.go
  • shortcuts/feed/shortcuts.go
  • shortcuts/feed/shortcuts_test.go
  • shortcuts/register.go
  • skills/lark-feed/SKILL.md
  • skills/lark-feed/references/lark-feed-sensitive.md
  • tests_e2e/feed/2026_04_29_feed_sensitive_test.go

Comment on lines +59 to +62
userIDs := runtime.StrSlice("user-ids")
if len(userIDs) == 0 {
return output.ErrValidation("--user-ids is required and must not be empty")
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Strengthen --user-ids validation to reject blank elements.
Line 60 only checks list length; values like --user-ids "," or whitespace-only entries can still pass.

🛠️ Suggested patch
 import (
 	"context"
 	"fmt"
 	"io"
+	"strings"

 	"github.com/larksuite/cli/internal/output"
 	"github.com/larksuite/cli/internal/validate"
 	"github.com/larksuite/cli/shortcuts/common"
 )
@@
 		userIDs := runtime.StrSlice("user-ids")
 		if len(userIDs) == 0 {
 			return output.ErrValidation("--user-ids is required and must not be empty")
 		}
+		for _, id := range userIDs {
+			if strings.TrimSpace(id) == "" {
+				return output.ErrValidation("--user-ids must not contain empty values")
+			}
+		}

 		return nil
 	},
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
userIDs := runtime.StrSlice("user-ids")
if len(userIDs) == 0 {
return output.ErrValidation("--user-ids is required and must not be empty")
}
import (
"context"
"fmt"
"io"
"strings"
"github.com/larksuite/cli/internal/output"
"github.com/larksuite/cli/internal/validate"
"github.com/larksuite/cli/shortcuts/common"
)
// ... (other code)
Validate: func(ctx context.Context, _ *flags.FlagSet) *output.Result {
userIDs := runtime.StrSlice("user-ids")
if len(userIDs) == 0 {
return output.ErrValidation("--user-ids is required and must not be empty")
}
for _, id := range userIDs {
if strings.TrimSpace(id) == "" {
return output.ErrValidation("--user-ids must not contain empty values")
}
}
return nil
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/feed/feed_sensitive.go` around lines 59 - 62, The current check
only ensures userIDs has non-zero length but allows blank or whitespace-only
elements; after retrieving userIDs := runtime.StrSlice("user-ids"), iterate the
slice, trim each entry using strings.TrimSpace and reject if any trimmed value
== "" (return output.ErrValidation with a clear message like "--user-ids must
not contain empty values"); optionally replace the slice with the
cleaned/trimmed values (e.g., build a new slice of trimmed IDs) before further
use so downstream code receives normalized IDs.

Comment on lines +120 to +136
func TestFeedSensitive_DryRunFlagBehavior(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
t.Cleanup(cancel)

t.Run("dry-run prints PATCH preview", func(t *testing.T) {
result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{
"feed", "+sensitive",
"--feed-card-id", "oc_dryruntestid",
"--enable",
"--user-ids", sandboxUserOpenID,
"--dry-run",
},
DefaultAs: "bot",
})
require.NoError(t, err)
result.AssertExitCode(t, 0)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify where RunCmd is implemented and whether required env vars are injected there.
fd -i '.*\.go' tests | xargs rg -n -C3 'func RunCmd|LARKSUITE_CLI_CONFIG_DIR|LARKSUITE_CLI_APP_ID|LARKSUITE_CLI_APP_SECRET|LARKSUITE_CLI_BRAND'

Repository: larksuite/cli

Length of output: 9319


🏁 Script executed:

fd -i '*feed*sensitive*test.go' tests/

Repository: larksuite/cli

Length of output: 360


🏁 Script executed:

fd -g '*feed*sensitive*test.go' tests/

Repository: larksuite/cli

Length of output: 39


🏁 Script executed:

find . -name '*feed*sensitive*test.go' -type f

Repository: larksuite/cli

Length of output: 148


🏁 Script executed:

cat -n ./tests_e2e/feed/2026_04_29_feed_sensitive_test.go

Repository: larksuite/cli

Length of output: 11120


🏁 Script executed:

find ./tests_e2e -name '*_test.go' -type f | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && head -40 {}'

Repository: larksuite/cli

Length of output: 1491


Add environment isolation to the dry-run test to prevent reading real credentials.

The TestFeedSensitive_DryRunFlagBehavior test (lines 120–146) is a dry-run E2E test but does not set LARKSUITE_CLI_CONFIG_DIR, LARKSUITE_CLI_APP_ID, LARKSUITE_CLI_APP_SECRET, or LARKSUITE_CLI_BRAND. Without this isolation, the subprocess can read a developer's real credentials from the local machine instead of the fake ones needed for --dry-run.

All other dry-run E2E tests in the repository follow this pattern:

  • drive_apply_permission_dryrun_test.go (L32–35)
  • drive_search_dryrun_test.go (L334–337)
  • mail_share_to_chat_dryrun_test.go (L23–26)
  • calendar_update_dryrun_test.go (L17–20)

Add a helper function to set these vars before calling RunCmd, or inline them in the test like the existing examples.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests_e2e/feed/2026_04_29_feed_sensitive_test.go` around lines 120 - 136, The
dry-run test TestFeedSensitive_DryRunFlagBehavior must not read real developer
credentials; before calling clie2e.RunCmd, set LARKSUITE_CLI_CONFIG_DIR,
LARKSUITE_CLI_APP_ID, LARKSUITE_CLI_APP_SECRET, and LARKSUITE_CLI_BRAND to fake
values (either by adding them to the clie2e.Request env/Env field if supported
or by calling os.Setenv with defer restore) so the subprocess is isolated;
implement this inline in TestFeedSensitive_DryRunFlagBehavior (or add a small
helper used by this test and other dry-run tests) and then call clie2e.RunCmd as
before.

Comment on lines +237 to +260
// createChatForFeed creates a private group chat via im +chat-create and
// returns the chat_id (which doubles as the feed_card_id for feed tests).
// No cleanup is registered because lark-cli im has no chat-delete command.
func createChatForFeed(t *testing.T, parentT *testing.T, ctx context.Context, name string) string {
t.Helper()

result, err := clie2e.RunCmd(ctx, clie2e.Request{
Args: []string{
"im", "+chat-create",
"--name", name,
"--type", "private",
},
DefaultAs: "bot",
})
require.NoError(t, err)
result.AssertExitCode(t, 0)
result.AssertStdoutStatus(t, true)

chatID := gjson.Get(result.Stdout, "data.chat_id").String()
require.NotEmpty(t, chatID, "chat_id must not be empty, stdout:\n%s", result.Stdout)

// No chat-delete command exists in lark-cli im; chats are left in the account.
_ = parentT

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Live E2E chat creation should include cleanup flow.

Leaving chats behind introduces long-term state pollution and potential quota/noise issues in shared environments. Please add best-effort cleanup in t.Cleanup (via available CLI/API path), even if failures are non-fatal.

Based on learnings: "Live E2E tests must be self-contained with create/use/cleanup flows and placed in tests/cli_e2e/<domain>/."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests_e2e/feed/2026_04_29_feed_sensitive_test.go` around lines 237 - 260,
createChatForFeed currently leaves created chats behind; add a best-effort
cleanup by registering t.Cleanup in createChatForFeed to remove the chat_id when
the test finishes. After extracting chatID (in createChatForFeed), call
t.Cleanup(func(){ ... }) that attempts to delete the chat using the available
removal path (e.g. use clie2e.RunCmd with the appropriate "im +chat-delete" args
if supported, or call the API client used elsewhere in tests), ensure deletion
failures are non-fatal but logged (use t.Log or t.Errorf), and remove the unused
parentT handling; keep the cleanup best-effort and tolerant of missing delete
commands/errors.

@jinzemo jinzemo closed this Apr 29, 2026
@jinzemo jinzemo deleted the feat/im-feed-card-time-sensitive branch April 29, 2026 12:02
@jinzemo jinzemo restored the feat/im-feed-card-time-sensitive branch April 29, 2026 12:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants