Skip to content

fix: migrate contact errors to typed taxonomy#1287

Open
evandance wants to merge 1 commit into
mainfrom
feat/errs-migrate-contact
Open

fix: migrate contact errors to typed taxonomy#1287
evandance wants to merge 1 commit into
mainfrom
feat/errs-migrate-contact

Conversation

@evandance
Copy link
Copy Markdown
Collaborator

@evandance evandance commented Jun 5, 2026

Summary

Migrate the contact shortcut domain to the typed errs.* taxonomy and lock the domain into the migration guards. This keeps contact command failures structured and machine-actionable without changing successful output contracts.

Changes

  • Replace contact validation failures and legacy common helpers with typed validation errors carrying param / params.
  • Route contact API responses through CallAPITyped / ClassifyAPIResponse, preserving typed API, network, auth, log_id, and code metadata.
  • Keep +search-user --queries partial-failure payload shape stable while returning typed errors when every query fails.
  • Add shortcuts/contact/ to forbidigo and errscontract migrated-path guards, and update tests away from legacy output.ExitError assertions.

Test Plan

  • /Users/bytedance/sdk/go1.23.10/bin/gofmt -l .
  • /Users/bytedance/sdk/go1.23.10/bin/go test ./shortcuts/contact ./internal/errclass
  • /Users/bytedance/sdk/go1.23.10/bin/go vet ./...
  • /Users/bytedance/sdk/go1.23.10/bin/go run -C lint . ..
  • go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.1.6 run --new-from-rev=origin/main with Go 1.23.10 on PATH
  • go mod tidy produced no go.mod / go.sum diff
  • make unit-test completed contact and most packages, but failed in unrelated timeout tests: internal/binding TestResolveExecRef_MissingID and internal/selfupdate TestVerifyBinaryLookPath.
  • Manual local verification confirms the lark-cli contact +get-user / +search-user error paths are covered by targeted unit tests and migrated lint guards.

Related Issues

  • None

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling and validation feedback in contact operations for better user experience.
  • Refactor

    • Migrated internal error handling to structured error types for contact shortcuts, enhancing error classification and diagnostics.
  • Tests

    • Updated test assertions to validate enhanced error information and categorization in contact search operations.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

The PR migrates the shortcuts/contact/ domain to use structured typed errors (errs package) and classified API responses. Linter rules mark the directory as migrated, API calls switch to CallAPITyped, validations emit ValidationErrorf with structured parameters, and fanout error handling captures and propagates metadata through the typed error system.

Changes

Typed Error Migration for Contact Domain

Layer / File(s) Summary
Linter Configuration for Migration Checkpoint
.golangci.yml, lint/errscontract/rule_no_legacy_common_helper_call.go, lint/errscontract/rule_no_legacy_envelope_literal.go
shortcuts/contact/ is registered as migrated across three forbidigo rules (errs-typed-only, errs-no-bare-wrap, errs-no-legacy-helper) in .golangci.yml, and the corresponding path allowlists in both rule implementation files are updated to enforce typed error patterns in that directory.
Get-User API Calls and Validation Migration
shortcuts/contact/contact_get_user.go
Three API calls (authen/v1/user_info, contact/v3/users/:user_id, contact/v3/users/basic_batch) switch from runtime.CallAPI to runtime.CallAPITyped, and bot-without-ID validation now emits ValidationErrorf with WithParam("--user-id") instead of FlagErrorf.
Search User Single Execution and Validation Refactoring
shortcuts/contact/contact_search_user.go
executeSearchUserSingle replaces manual HTTP status checking and envelope unmarshalling with runtime.ClassifyAPIResponse and a new decodeSearchUserAPIData helper; validation refactored to emit common.ValidationErrorf with structured errs.InvalidParam entries for missing inputs, mutual exclusivity, parsed constraints, and rune/page-size limits; --user-ids resolution switched to common.ResolveOpenIDsTyped.
Fanout Result Structure and Error Propagation
shortcuts/contact/contact_search_user_fanout.go
fanoutResult extended with structured metadata fields (ErrCat, ErrSub, ErrHint, ErrLog, ErrTry); runOneQuery refactored to use ClassifyAPIResponse and decodeSearchUserAPIData with new error helpers; "all queries failed" logic in buildFanoutResponse maps error categories to typed constructors (errs.New*) or returns errs.NewInternalError with retry hints.
Test Updates for Typed Problem Validation
shortcuts/contact/contact_search_user_test.go
Fanout error-handling tests updated to validate errs.ProblemOf(err) fields (CategoryInternal, Code, Hint containing retry) instead of extracting output.ExitError details; imports adjusted to use errs instead of output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • larksuite/cli#648: Both PRs modify the contact +search-user implementation, especially around --user-ids handling/validation and request/response wiring.
  • larksuite/cli#711: Both PRs modify fanout and search-user code paths in shortcuts/contact/ with typed/structured error handling and corresponding tests.

Suggested labels

domain/contact, size/L

Suggested reviewers

  • liuxinyanglxy
  • sang-neo03
  • calendar-assistant

Poem

🐰 Typed errors hop through contact calls,
Validation fields catch every fall,
Fanout metadata spreads the word,
Structured hints get properly heard,
Linters nod—the migration's done!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% 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 'fix: migrate contact errors to typed taxonomy' accurately captures the main change, which is migrating contact domain errors to a typed error taxonomy system.
Description check ✅ Passed The description includes all required sections: Summary (motivation and scope), Changes (main changes listed with bullet points), Test Plan (with checkboxes and detailed testing steps), and Related Issues. The description is comprehensive and well-structured.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/errs-migrate-contact

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

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

@github-actions github-actions Bot added domain/contact PR touches the contact domain size/L Large or sensitive change across domains or core paths labels Jun 5, 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.

🧹 Nitpick comments (1)
shortcuts/contact/contact_search_user_fanout.go (1)

222-349: 💤 Low value

Consider extracting repeated builder logic to reduce duplication.

All 8 switch cases share identical conditional-chaining logic (WithCode, WithLogID, WithHint, WithRetryable). A small helper could cut this to ~30 lines while preserving behavior.

♻️ Optional refactor sketch
// applyMetadata applies optional fields and returns an error interface.
func applyMetadata(e interface {
	WithCode(int) interface{ WithLogID(string) interface{ WithHint(string, ...any) interface{ WithRetryable() error } } }
	// ... or define a shared TypedErrorBuilder interface in errs package
}, first fanoutResult) error {
	if first.ErrCode != 0 {
		e = e.WithCode(first.ErrCode)
	}
	if first.ErrLog != "" {
		e = e.WithLogID(first.ErrLog)
	}
	if first.ErrHint != "" {
		e = e.WithHint("%s", first.ErrHint)
	}
	if first.ErrTry {
		return e.WithRetryable()
	}
	return e.(error)
}

func fanoutAllFailedError(first fanoutResult, msg string) error {
	subtype := first.ErrSub
	if subtype == "" {
		subtype = errs.SubtypeUnknown
	}
	var base interface{ ... } // typed error
	switch first.ErrCat {
	case errs.CategoryAuthentication:
		base = errs.NewAuthenticationError(subtype, "%s", msg)
	case errs.CategoryAuthorization:
		base = errs.NewPermissionError(subtype, "%s", msg)
	// ... other cases
	default:
		base = errs.NewAPIError(subtype, "%s", msg)
	}
	return applyMetadata(base, first)
}

This depends on whether the errs package exposes a common builder interface. If not, the current explicit approach is fine—just verbose.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shortcuts/contact/contact_search_user_fanout.go` around lines 222 - 349, The
fanoutAllFailedError function repeats identical builder chaining across each
error case; extract that duplication by creating a helper (e.g., applyMetadata)
that accepts the error builder returned from errs.NewAuthenticationError /
NewPermissionError / NewConfigError / NewNetworkError / NewValidationError /
NewSecurityPolicyError / NewInternalError / NewAPIError and the fanoutResult,
applies WithCode, WithLogID, WithHint and WithRetryable conditionally, and
returns the final error; you can implement a small interface for the builder
either locally or in the errs package to type the helper, then simplify
fanoutAllFailedError to only choose the base error by ErrCat and call
applyMetadata(base, first).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@shortcuts/contact/contact_search_user_fanout.go`:
- Around line 222-349: The fanoutAllFailedError function repeats identical
builder chaining across each error case; extract that duplication by creating a
helper (e.g., applyMetadata) that accepts the error builder returned from
errs.NewAuthenticationError / NewPermissionError / NewConfigError /
NewNetworkError / NewValidationError / NewSecurityPolicyError / NewInternalError
/ NewAPIError and the fanoutResult, applies WithCode, WithLogID, WithHint and
WithRetryable conditionally, and returns the final error; you can implement a
small interface for the builder either locally or in the errs package to type
the helper, then simplify fanoutAllFailedError to only choose the base error by
ErrCat and call applyMetadata(base, first).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 117150c8-65bb-492e-9a4b-dd6c7e1b7ab0

📥 Commits

Reviewing files that changed from the base of the PR and between f3949f0 and 1bf7eef.

📒 Files selected for processing (7)
  • .golangci.yml
  • lint/errscontract/rule_no_legacy_common_helper_call.go
  • lint/errscontract/rule_no_legacy_envelope_literal.go
  • shortcuts/contact/contact_get_user.go
  • shortcuts/contact/contact_search_user.go
  • shortcuts/contact/contact_search_user_fanout.go
  • shortcuts/contact/contact_search_user_test.go

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 5, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@1bf7eef20b9975c4e1014619a1a8ca407c5ec37f

🧩 Skill update

npx skills add larksuite/cli#feat/errs-migrate-contact -y -g

@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 5, 2026

Codecov Report

❌ Patch coverage is 52.55102% with 93 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.27%. Comparing base (f3949f0) to head (1bf7eef).

Files with missing lines Patch % Lines
shortcuts/contact/contact_search_user_fanout.go 42.64% 72 Missing and 6 partials ⚠️
shortcuts/contact/contact_search_user.go 81.81% 6 Missing and 4 partials ⚠️
shortcuts/contact/contact_get_user.go 0.00% 5 Missing ⚠️

❌ Your patch check has failed because the patch coverage (52.55%) is below the target coverage (60.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1287      +/-   ##
==========================================
- Coverage   70.33%   70.27%   -0.06%     
==========================================
  Files         672      672              
  Lines       65322    65467     +145     
==========================================
+ Hits        45941    46006      +65     
- Misses      15728    15802      +74     
- Partials     3653     3659       +6     

☔ View full report in Codecov by Harness.
📢 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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

Labels

domain/contact PR touches the contact domain size/L Large or sensitive change across domains or core paths

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant