Skip to content

feat: add TestGenerateShortcutsJSON and skip redundant meta fetch#179

Merged
MaxHuang22 merged 2 commits intomainfrom
feat/gen-skill
Apr 1, 2026
Merged

feat: add TestGenerateShortcutsJSON and skip redundant meta fetch#179
MaxHuang22 merged 2 commits intomainfrom
feat/gen-skill

Conversation

@MaxHuang22
Copy link
Copy Markdown
Collaborator

@MaxHuang22 MaxHuang22 commented Apr 1, 2026

Summary

  • Add TestGenerateShortcutsJSON in shortcuts/register_test.go: exports all shortcuts as JSON when SHORTCUTS_OUTPUT env var is set, enabling the registry repo to extract shortcut metadata without a dump-shortcuts CLI command. Skips automatically when env is not set (zero CI impact).
  • Update scripts/fetch_meta.py to skip downloading when meta_data.json already exists locally, preventing overwrite of registry-generated versions during build.

Test plan

  • go test ./shortcuts/... — all existing tests pass, TestGenerateShortcutsJSON shows SKIP
  • SHORTCUTS_OUTPUT=/tmp/test.json go test -run TestGenerateShortcutsJSON ./shortcuts/... — generates valid JSON
  • ./build.sh with existing meta_data.json — skips fetch, prints skip message
  • ./build.sh without meta_data.json — fetches from remote as before

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Script adds a --force option and now preserves existing metadata output by default, re-fetching only when forced or when the existing file is empty/invalid.
  • Tests

    • Added a test that generates grouped shortcuts JSON to a configurable output path, creating directories as needed and reporting failures on write errors.

Add a test that exports all shortcuts as JSON when SHORTCUTS_OUTPUT
env var is set, enabling the registry repo to extract shortcut
metadata without depending on a dump-shortcuts CLI command.

Change-Id: I9e450fdcb579d6a21ac8ec36e4197728bb7408bb
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d89373f3-7c33-40be-bcc2-1df8b35f9d79

📥 Commits

Reviewing files that changed from the base of the PR and between 88e6a9c and 0d0c64d.

📒 Files selected for processing (1)
  • scripts/fetch_meta.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/fetch_meta.py

📝 Walkthrough

Walkthrough

A script (scripts/fetch_meta.py) now avoids overwriting internal/registry/meta_data.json by checking the file and its services content unless --force is provided; a new test (shortcuts/register_test.go) generates and writes grouped shortcut metadata to a path from SHORTCUTS_OUTPUT.

Changes

Cohort / File(s) Summary
Conditional Fetch Guard
scripts/fetch_meta.py
main() gains a --force flag; if OUT_PATH exists and --force is not set, the script attempts to read JSON and returns early if services is non-empty; invalid/unreadable/non-regular files or empty services trigger a re-fetch.
Shortcut Metadata Test
shortcuts/register_test.go
Added TestGenerateShortcutsJSON which reads SHORTCUTS_OUTPUT env var, groups AllShortcuts() by service, derives verb by trimming a leading +, populates Description and ScopesForIdentity("user"), marshals with json.MarshalIndent, ensures the output directory, and writes the file. New imports: encoding/json, os, path/filepath, strings.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I checked the meta door, gentle and bright,
Kept the old file safe unless forced to write.
I hopped through shortcuts, trimmed a tiny plus,
Wrote JSON paths for testers to trust us. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes both main changes: adding TestGenerateShortcutsJSON and making meta fetch conditional based on local file existence.
Description check ✅ Passed The PR description covers all template sections with clear details: comprehensive summary of both changes, complete test plan with checkmarks showing all tests passed, and appropriate formatting.

✏️ 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/gen-skill

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 1, 2026

Greptile Summary

This PR introduces two quality-of-life improvements: a TestGenerateShortcutsJSON test that serialises all registered shortcuts to a JSON file when SHORTCUTS_OUTPUT is set (enabling a downstream registry repo to extract shortcut metadata without a dedicated CLI command), and a skip-if-valid-exists guard in scripts/fetch_meta.py that prevents overwriting a locally present meta_data.json during builds (with a new --force flag to override).

Key changes and observations:

  • scripts/fetch_meta.py: The new guard reads the existing file, checks that it contains a non-empty services key, and skips the remote fetch if valid. The --force flag gives an explicit override path. The prior concern about silently using the wrong brand's data on skip is partially addressed (users can use --force --brand lark to re-fetch), though the skip message still does not surface which brand was requested.
  • shortcuts/register_test.go: The generator groups shortcuts by service into a map[string][]entry and uses ScopesForIdentity(\"user\") to populate scopes. Data-correctness concerns raised in the prior review — specifically that bot-only shortcuts produce \"scopes\": null in the output and that map iteration produces non-deterministic key ordering across runs — remain unaddressed in this revision.

Confidence Score: 4/5

Safe to merge for build functionality, but the generated shortcuts JSON may contain null scopes and non-deterministic ordering, making it unreliable as a machine-readable artifact for the downstream registry.

The fetch_meta.py skip logic is solid and the --force escape hatch is a good addition. However, two data-correctness issues in the primary deliverable (the shortcuts JSON generator) flagged in the prior review remain open: bot-only shortcuts emit "scopes": null instead of [] and map iteration produces different key order on every run. If the downstream registry diffs or commits this file, both issues will cause recurring noise or incorrect data. These warrant resolution before the test is put into active use.

shortcuts/register_test.go — nil-scopes normalisation and deterministic key ordering should be addressed before the generated file is consumed by the registry repo.

Important Files Changed

Filename Overview
shortcuts/register_test.go Adds TestGenerateShortcutsJSON that serialises all shortcuts to a file when SHORTCUTS_OUTPUT is set; data-quality concerns noted in prior review (nil scopes → JSON null, non-deterministic map key ordering) remain unaddressed.
scripts/fetch_meta.py Adds skip-if-exists logic with content validation (services key check) and a --force override; the brand-mismatch-on-skip concern from the prior review is partially mitigated by --force but not fully resolved.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[fetch_meta.py invoked] --> B{--force flag?}
    B -- Yes --> F[fetch_remote brand]
    B -- No --> C{OUT_PATH exists?}
    C -- No --> F
    C -- Yes --> D{is a file?}
    D -- No --> F
    D -- Yes --> E{Valid JSON with services key?}
    E -- No / empty --> F
    E -- Yes --> G[Skip: print msg to stderr, return 0]
    F --> H[Write meta_data.json to disk]
Loading

Reviews (2): Last reviewed commit: "fix: skip fetch_meta.py when meta_data.j..." | Re-trigger Greptile

Comment thread scripts/fetch_meta.py Outdated
Comment thread shortcuts/register_test.go
Comment thread shortcuts/register_test.go
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 1, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@0d0c64dbf8cbe03d1dd2cad187427f5ab1c2fd42

🧩 Skill update

npx skills add larksuite/cli#feat/gen-skill -y -g

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/fetch_meta.py (1)

67-74: ⚠️ Potential issue | 🟠 Major

Validate existing metadata before skipping, and add a force refresh path.

Line 72 currently checks only path existence. If internal/registry/meta_data.json is corrupt/empty (or not a regular file), fetch is skipped and build keeps invalid metadata. Also, this makes explicit refreshes awkward when --brand changes.

Suggested patch
 def main():
     parser = argparse.ArgumentParser(description="Fetch meta_data.json for build-time embedding")
     parser.add_argument("--brand", default="feishu", choices=["feishu", "lark"],
                         help="API brand (default: feishu)")
+    parser.add_argument("--force", action="store_true",
+                        help="force refresh from remote even if local file exists")
     args = parser.parse_args()

-    if os.path.exists(OUT_PATH):
-        print(f"fetch-meta: {OUT_PATH} already exists, skipping (delete to re-fetch)", file=sys.stderr)
-        return
+    if os.path.exists(OUT_PATH) and not args.force:
+        if os.path.isfile(OUT_PATH):
+            try:
+                with open(OUT_PATH, "r", encoding="utf-8") as fp:
+                    local = json.load(fp)
+                if local.get("services"):
+                    print(f"fetch-meta: {OUT_PATH} already exists, skipping (use --force to re-fetch)", file=sys.stderr)
+                    return
+                print(f"fetch-meta: {OUT_PATH} has no services, re-fetching", file=sys.stderr)
+            except (OSError, json.JSONDecodeError):
+                print(f"fetch-meta: {OUT_PATH} is invalid JSON, re-fetching", file=sys.stderr)
+        else:
+            print(f"fetch-meta: {OUT_PATH} is not a file, re-fetching", file=sys.stderr)

     data = fetch_remote(args.brand)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/fetch_meta.py` around lines 67 - 74, The existing skip logic only
checks OUT_PATH existence; change it to validate it's a regular file
(os.path.isfile), non-empty (os.path.getsize>0), and that its contents parse as
valid JSON and — if present — contain a matching "brand" field equal to
args.brand; add a --force (or -f) boolean argparse flag to override validation
and force re-fetch. In practice update the parser to include
parser.add_argument("--force", action="store_true", help="force refresh"), then
replace the current if os.path.exists(OUT_PATH) check with a block that returns
only when not args.force and the file is a regular non-empty file and
json.load(open(OUT_PATH)) succeeds (and the
parsed_data.get("brand")==args.brand); otherwise proceed to re-fetch and
overwrite OUT_PATH.
🧹 Nitpick comments (1)
shortcuts/register_test.go (1)

104-116: Include bot identity scopes in exported shortcuts registry.

Line 115 exports only user scopes via s.ScopesForIdentity("user"). At least 4 shortcuts declare distinct bot scopes (e.g., im_threads_messages_list, contact_get_user), and 4 shortcuts are bot-only (e.g., im_chat_create, event/subscribe). The exported JSON loses this metadata.

Update the entry struct to include scopes for all declared identities in AuthTypes:

Suggested schema change
 	type entry struct {
 		Verb        string   `json:"verb"`
 		Description string   `json:"description"`
-		Scopes      []string `json:"scopes"`
+		Scopes      map[string][]string `json:"scopes"`
 	}
@@
 		grouped[s.Service] = append(grouped[s.Service], entry{
 			Verb:        verb,
 			Description: s.Description,
-			Scopes:      s.ScopesForIdentity("user"),
+			Scopes: func() map[string][]string {
+				scopes := make(map[string][]string)
+				for _, id := range s.AuthTypes {
+					scopes[id] = s.ScopesForIdentity(id)
+				}
+				return scopes
+			}(),
 		})
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/register_test.go` around lines 104 - 116, The exported entry
currently only includes user scopes; update the entry struct (the type entry) to
include a map of scopes per identity (e.g., ScopesByIdentity
map[string][]string) instead of (or in addition to) the single Scopes field,
then in the loop over shortcuts (for _, s := range shortcuts) populate that map
by iterating the identities in AuthTypes and calling
s.ScopesForIdentity(identity) for each identity so bot scopes (and any other
identities) are preserved in grouped[s.Service] entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@scripts/fetch_meta.py`:
- Around line 67-74: The existing skip logic only checks OUT_PATH existence;
change it to validate it's a regular file (os.path.isfile), non-empty
(os.path.getsize>0), and that its contents parse as valid JSON and — if present
— contain a matching "brand" field equal to args.brand; add a --force (or -f)
boolean argparse flag to override validation and force re-fetch. In practice
update the parser to include parser.add_argument("--force", action="store_true",
help="force refresh"), then replace the current if os.path.exists(OUT_PATH)
check with a block that returns only when not args.force and the file is a
regular non-empty file and json.load(open(OUT_PATH)) succeeds (and the
parsed_data.get("brand")==args.brand); otherwise proceed to re-fetch and
overwrite OUT_PATH.

---

Nitpick comments:
In `@shortcuts/register_test.go`:
- Around line 104-116: The exported entry currently only includes user scopes;
update the entry struct (the type entry) to include a map of scopes per identity
(e.g., ScopesByIdentity map[string][]string) instead of (or in addition to) the
single Scopes field, then in the loop over shortcuts (for _, s := range
shortcuts) populate that map by iterating the identities in AuthTypes and
calling s.ScopesForIdentity(identity) for each identity so bot scopes (and any
other identities) are preserved in grouped[s.Service] entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fef8427f-569d-4e0a-a912-d4a54019fa78

📥 Commits

Reviewing files that changed from the base of the PR and between d4e83df and 88e6a9c.

📒 Files selected for processing (2)
  • scripts/fetch_meta.py
  • shortcuts/register_test.go

Avoid overwriting a locally generated meta_data.json with the
remote version during build.

Change-Id: Ic30d70b9fa9d9c8e060879e4000c53c58f3aa525
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MaxHuang22 MaxHuang22 merged commit eb8b542 into main Apr 1, 2026
11 checks passed
@MaxHuang22 MaxHuang22 deleted the feat/gen-skill branch April 1, 2026 12:14
tuxedomm pushed a commit that referenced this pull request Apr 3, 2026
* feat: add TestGenerateShortcutsJSON for registry shortcut export

Add a test that exports all shortcuts as JSON when SHORTCUTS_OUTPUT
env var is set, enabling the registry repo to extract shortcut
metadata without depending on a dump-shortcuts CLI command.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants