mirror of
https://github.com/larksuite/cli.git
synced 2026-07-08 10:08:02 +08:00
fix: close install gaps aligned with fullstack-cli
- latest version: re-check installed version after API resolves, skip download when already up to date - actionPlugins sync: ensure package.json record is updated even when install is skipped (already_installed path) - peerDependencies: warn about missing peer deps after extraction instead of silently ignoring them
This commit is contained in:
@@ -506,6 +506,47 @@ func pluginRemoveActionPlugin(pkg map[string]interface{}, key string) {
|
||||
delete(m, key)
|
||||
}
|
||||
|
||||
// pluginSyncActionPlugins ensures the actionPlugins record in package.json
|
||||
// matches the actually installed version, even when install is skipped.
|
||||
func pluginSyncActionPlugins(projectPath, key, version string) {
|
||||
pkg, err := pluginReadPackageJSON(projectPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ap := pluginGetActionPlugins(pkg)
|
||||
if ap[key] == version {
|
||||
return
|
||||
}
|
||||
pluginSetActionPlugin(pkg, key, version)
|
||||
_ = pluginWritePackageJSON(projectPath, pkg)
|
||||
}
|
||||
|
||||
// pluginCheckPeerDeps reads peerDependencies from the installed plugin's
|
||||
// package.json and returns the names of any that are missing from node_modules.
|
||||
func pluginCheckPeerDeps(projectPath, pluginKey string) []string {
|
||||
pkgPath := filepath.Join(projectPath, "node_modules", pluginKey, "package.json")
|
||||
data, err := os.ReadFile(pkgPath) //nolint:forbidigo // shortcuts cannot import internal/vfs; local package read.
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var pkg map[string]interface{}
|
||||
if err := json.Unmarshal(data, &pkg); err != nil {
|
||||
return nil
|
||||
}
|
||||
peerDeps, ok := pkg["peerDependencies"].(map[string]interface{})
|
||||
if !ok || len(peerDeps) == 0 {
|
||||
return nil
|
||||
}
|
||||
var missing []string
|
||||
for dep := range peerDeps {
|
||||
depDir := filepath.Join(projectPath, "node_modules", dep)
|
||||
if !pluginDirExists(depDir) {
|
||||
missing = append(missing, dep)
|
||||
}
|
||||
}
|
||||
return missing
|
||||
}
|
||||
|
||||
// pluginParseInstallTarget parses "key[@version]" where version is optional.
|
||||
// For scoped packages like "@scope/name@1.0.0", the split is at the last "@".
|
||||
func pluginParseInstallTarget(s string) (key string, version string) {
|
||||
|
||||
@@ -77,9 +77,10 @@ func pluginInstallOne(ctx context.Context, rctx *common.RuntimeContext, projectP
|
||||
return appsValidationParamError("--name", "invalid plugin name %q", name)
|
||||
}
|
||||
|
||||
// Check if already installed with same version
|
||||
// Check if already installed with same version (pre-API fast path)
|
||||
if version != "" && version != "latest" {
|
||||
if installed := pluginInstalledVersion(projectPath, key); installed == version {
|
||||
pluginSyncActionPlugins(projectPath, key, version)
|
||||
result := map[string]interface{}{
|
||||
"key": key, "version": version, "status": "already_installed",
|
||||
}
|
||||
@@ -96,6 +97,18 @@ func pluginInstallOne(ctx context.Context, rctx *common.RuntimeContext, projectP
|
||||
return err
|
||||
}
|
||||
|
||||
// Post-API check: latest may resolve to the already-installed version
|
||||
if installed := pluginInstalledVersion(projectPath, key); installed == resolvedVersion {
|
||||
pluginSyncActionPlugins(projectPath, key, resolvedVersion)
|
||||
result := map[string]interface{}{
|
||||
"key": key, "version": resolvedVersion, "status": "already_installed",
|
||||
}
|
||||
rctx.OutFormat(result, nil, func(w io.Writer) {
|
||||
fmt.Fprintf(w, "✓ %s@%s is already up to date\n", key, resolvedVersion)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// Download tgz
|
||||
tgzData, err := pluginDownloadPackage(ctx, rctx, key, resolvedVersion, downloadURL, approach)
|
||||
if err != nil {
|
||||
@@ -114,6 +127,9 @@ func pluginInstallOne(ctx context.Context, rctx *common.RuntimeContext, projectP
|
||||
return appsFileIOError(err, "cannot extract plugin package for %s", key)
|
||||
}
|
||||
|
||||
// Check peer dependencies
|
||||
missingPeers := pluginCheckPeerDeps(projectPath, key)
|
||||
|
||||
// Update package.json
|
||||
pkg, err := pluginReadPackageJSON(projectPath)
|
||||
if err != nil {
|
||||
@@ -127,8 +143,15 @@ func pluginInstallOne(ctx context.Context, rctx *common.RuntimeContext, projectP
|
||||
result := map[string]interface{}{
|
||||
"key": key, "version": resolvedVersion, "status": "installed",
|
||||
}
|
||||
if len(missingPeers) > 0 {
|
||||
result["missing_peer_dependencies"] = missingPeers
|
||||
}
|
||||
rctx.OutFormat(result, nil, func(w io.Writer) {
|
||||
fmt.Fprintf(w, "✓ Installed %s@%s\n", key, resolvedVersion)
|
||||
if len(missingPeers) > 0 {
|
||||
fmt.Fprintf(w, "⚠ Missing peer dependencies: %s\n", strings.Join(missingPeers, ", "))
|
||||
fmt.Fprintln(w, " Run 'npm install' in the project directory to install them.")
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user