Add RenameLocalApp function to waveappstore (#2536)

## Plan: Add RenameLocalApp function to waveappstore

- [x] Analyze existing code patterns in waveappstore.go
- [x] Implement RenameLocalApp(appName string, newAppName string) error
function
  - Validate newAppName using existing validation
- Check if local/[appname] exists and rename to local/[newAppName] if it
does
- Check if draft/[appname] exists and rename to draft/[newAppName] if it
does
  - Handle errors appropriately including rollback on partial failure
- [x] Add documentation comments
- [x] Run security checks (CodeQL - no issues found)

## Summary

Successfully implemented `RenameLocalApp(appName string, newAppName
string) error` function that:
- Renames local apps in both `local/` and `draft/` namespaces
- Validates app names and checks for conflicts
- Implements proper error handling with rollback on partial failure
- Passes all security checks with zero vulnerabilities



Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
This commit is contained in:
Copilot 2025-11-10 16:46:52 -08:00 committed by GitHub
parent 8c50f7b0b3
commit f12ae1ee78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -498,7 +498,6 @@ func ListAllEditableApps() ([]string, error) {
return appIds, nil
}
func DraftHasLocalVersion(draftAppId string) (bool, error) {
if err := ValidateAppId(draftAppId); err != nil {
return false, fmt.Errorf("invalid appId: %w", err)
@ -521,3 +520,84 @@ func DraftHasLocalVersion(draftAppId string) (bool, error) {
return true, nil
}
// RenameLocalApp renames a local app by renaming its directories in both the local and draft namespaces.
// It takes the current app name and the new app name (without namespace prefixes).
// Both local/[appName] and draft/[appName] will be renamed if they exist.
// Returns an error if the app doesn't exist in either namespace, if the new name is invalid,
// or if the new name conflicts with an existing app.
func RenameLocalApp(appName string, newAppName string) error {
// Validate the old app name by constructing a valid appId
oldLocalAppId := MakeAppId(AppNSLocal, appName)
if err := ValidateAppId(oldLocalAppId); err != nil {
return fmt.Errorf("invalid app name: %w", err)
}
// Validate the new app name by constructing a valid appId
newLocalAppId := MakeAppId(AppNSLocal, newAppName)
if err := ValidateAppId(newLocalAppId); err != nil {
return fmt.Errorf("invalid new app name: %w", err)
}
homeDir := wavebase.GetHomeDir()
waveappsDir := filepath.Join(homeDir, "waveapps")
oldLocalDir := filepath.Join(waveappsDir, AppNSLocal, appName)
newLocalDir := filepath.Join(waveappsDir, AppNSLocal, newAppName)
oldDraftDir := filepath.Join(waveappsDir, AppNSDraft, appName)
newDraftDir := filepath.Join(waveappsDir, AppNSDraft, newAppName)
// Check if at least one of the apps exists
localExists := false
draftExists := false
if _, err := os.Stat(oldLocalDir); err == nil {
localExists = true
} else if !os.IsNotExist(err) {
return fmt.Errorf("failed to check local app: %w", err)
}
if _, err := os.Stat(oldDraftDir); err == nil {
draftExists = true
} else if !os.IsNotExist(err) {
return fmt.Errorf("failed to check draft app: %w", err)
}
if !localExists && !draftExists {
return fmt.Errorf("app '%s' does not exist in local or draft namespace", appName)
}
// Check if new app name already exists in either namespace
if _, err := os.Stat(newLocalDir); err == nil {
return fmt.Errorf("local app '%s' already exists", newAppName)
} else if !os.IsNotExist(err) {
return fmt.Errorf("failed to check if new local app exists: %w", err)
}
if _, err := os.Stat(newDraftDir); err == nil {
return fmt.Errorf("draft app '%s' already exists", newAppName)
} else if !os.IsNotExist(err) {
return fmt.Errorf("failed to check if new draft app exists: %w", err)
}
// Rename local app if it exists
if localExists {
if err := os.Rename(oldLocalDir, newLocalDir); err != nil {
return fmt.Errorf("failed to rename local app: %w", err)
}
}
// Rename draft app if it exists
if draftExists {
if err := os.Rename(oldDraftDir, newDraftDir); err != nil {
// If local was renamed but draft fails, try to rollback local rename
if localExists {
if rollbackErr := os.Rename(newLocalDir, oldLocalDir); rollbackErr != nil {
return fmt.Errorf("failed to rename draft app (and failed to rollback local rename: %v): %w", rollbackErr, err)
}
}
return fmt.Errorf("failed to rename draft app: %w", err)
}
}
return nil
}