Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions cmd/completion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1047,3 +1047,179 @@ func TestCompleteVPCPeeringRouteID_TooManyArgs(t *testing.T) {
t.Errorf("expected nil completions with too many args, got %v", comps)
}
}

// ─── completeDBaaSDatabaseID parent-slot fixes ───────────────────────────────

func TestCompleteDBaaSDatabaseID_NoArgs_DelegatesToDBaaSID(t *testing.T) {
id, name := "dbaas-001", "my-dbaas"
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Database/dbaas", jsonResponse(200, types.DBaaSListResponse{
Values: []types.DBaaSResponse{
{Metadata: types.ResourceMetadataResponse{ID: &id, Name: &name}},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeDBaaSDatabaseID(makeProjectCmd("proj-123"), []string{}, "")
if len(completions) == 0 {
t.Errorf("expected DBaaS IDs from delegation, got none")
}
}

func TestCompleteDBaaSDatabaseID_NoArgs_NoProjectID(t *testing.T) {
cleanup := withTempHomeDir(t)
defer cleanup()

comps, _ := completeDBaaSDatabaseID(&cobra.Command{}, []string{}, "")
if comps != nil {
t.Errorf("expected nil completions without project-id, got %v", comps)
}
}

func TestCompleteDBaaSDatabaseID_TooManyArgs(t *testing.T) {
comps, _ := completeDBaaSDatabaseID(&cobra.Command{}, []string{"dbaas-001", "my-db"}, "")
if comps != nil {
t.Errorf("expected nil completions with too many args, got %v", comps)
}
}

// ─── completeDBaaSUserID parent-slot fixes ────────────────────────────────────

func TestCompleteDBaaSUserID_NoArgs_DelegatesToDBaaSID(t *testing.T) {
id, name := "dbaas-001", "my-dbaas"
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Database/dbaas", jsonResponse(200, types.DBaaSListResponse{
Values: []types.DBaaSResponse{
{Metadata: types.ResourceMetadataResponse{ID: &id, Name: &name}},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeDBaaSUserID(makeProjectCmd("proj-123"), []string{}, "")
if len(completions) == 0 {
t.Errorf("expected DBaaS IDs from delegation, got none")
}
}

func TestCompleteDBaaSUserID_NoArgs_NoProjectID(t *testing.T) {
cleanup := withTempHomeDir(t)
defer cleanup()

comps, _ := completeDBaaSUserID(&cobra.Command{}, []string{}, "")
if comps != nil {
t.Errorf("expected nil completions without project-id, got %v", comps)
}
}

func TestCompleteDBaaSUserID_TooManyArgs(t *testing.T) {
comps, _ := completeDBaaSUserID(&cobra.Command{}, []string{"dbaas-001", "alice"}, "")
if comps != nil {
t.Errorf("expected nil completions with too many args, got %v", comps)
}
}

// ─── completeGrantID parent-slot fixes ───────────────────────────────────────

func TestCompleteGrantID_NoArgs_DelegatesToDBaaSID(t *testing.T) {
id, name := "dbaas-001", "my-dbaas"
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Database/dbaas", jsonResponse(200, types.DBaaSListResponse{
Values: []types.DBaaSResponse{
{Metadata: types.ResourceMetadataResponse{ID: &id, Name: &name}},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeGrantID(makeProjectCmd("proj-123"), []string{}, "")
if len(completions) == 0 {
t.Errorf("expected DBaaS IDs from delegation, got none")
}
}

func TestCompleteGrantID_OneArg_DelegatesToDatabaseID(t *testing.T) {
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Database/dbaas/dbaas-001/databases", jsonResponse(200, types.DatabaseListResponse{
Values: []types.DatabaseResponse{
{Name: "my-db"},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeGrantID(makeProjectCmd("proj-123"), []string{"dbaas-001"}, "")
if len(completions) == 0 {
t.Errorf("expected database names from delegation, got none")
}
}

func TestCompleteGrantID_TooManyArgs(t *testing.T) {
comps, _ := completeGrantID(&cobra.Command{}, []string{"dbaas-001", "my-db", "grant-id"}, "")
if comps != nil {
t.Errorf("expected nil completions with too many args, got %v", comps)
}
}

// ─── completeStorageRestoreCreateArgs ────────────────────────────────────────

func TestCompleteStorageRestoreCreateArgs_NoArgs_DelegatesToBackupID(t *testing.T) {
id, name := "bkp-001", "my-backup"
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Storage/backups", jsonResponse(200, types.StorageBackupListResponse{
Values: []types.StorageBackupResponse{
{Metadata: types.ResourceMetadataResponse{ID: &id, Name: &name}},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeStorageRestoreCreateArgs(makeProjectCmd("proj-123"), []string{}, "")
if len(completions) == 0 {
t.Errorf("expected backup IDs from delegation, got none")
}
}

func TestCompleteStorageRestoreCreateArgs_OneArg_DelegatesToBlockStorageID(t *testing.T) {
id, name := "vol-001", "my-volume"
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Storage/blockStorages", jsonResponse(200, types.BlockStorageListResponse{
Values: []types.BlockStorageResponse{
{Metadata: types.ResourceMetadataResponse{ID: &id, Name: &name}},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeStorageRestoreCreateArgs(makeProjectCmd("proj-123"), []string{"bkp-001"}, "")
if len(completions) == 0 {
t.Errorf("expected volume IDs from delegation, got none")
}
}

func TestCompleteStorageRestoreCreateArgs_TooManyArgs(t *testing.T) {
comps, _ := completeStorageRestoreCreateArgs(&cobra.Command{}, []string{"bkp-001", "vol-001"}, "")
if comps != nil {
t.Errorf("expected nil completions with too many args, got %v", comps)
}
}

// ─── storageBackupCmd create ValidArgsFunction ───────────────────────────────

func TestCompleteBackupCreateArg_DelegatesToBlockStorageID(t *testing.T) {
id, name := "vol-001", "my-volume"
srv := newArubaTestServer(t)
srv.OnGet("/projects/proj-123/providers/Aruba.Storage/blockStorages", jsonResponse(200, types.BlockStorageListResponse{
Values: []types.BlockStorageResponse{
{Metadata: types.ResourceMetadataResponse{ID: &id, Name: &name}},
},
}))
setClientForTesting(srv.Client())
defer resetClientState()

completions, _ := completeBlockStorageID(makeProjectCmd("proj-123"), nil, "")
if len(completions) == 0 {
t.Errorf("expected volume IDs, got none")
}
}
7 changes: 6 additions & 1 deletion cmd/database.dbaas.database.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,18 @@ func init() {
dbaasDatabaseListCmd.Flags().Int("limit", 0, "Maximum number of results to return (0 = no limit)")
dbaasDatabaseListCmd.Flags().Int("offset", 0, "Number of results to skip")

dbaasDatabaseCreateCmd.ValidArgsFunction = completeDBaaSDatabaseID
dbaasDatabaseListCmd.ValidArgsFunction = completeDBaaSDatabaseID
dbaasDatabaseGetCmd.ValidArgsFunction = completeDBaaSDatabaseID
dbaasDatabaseUpdateCmd.ValidArgsFunction = completeDBaaSDatabaseID
dbaasDatabaseDeleteCmd.ValidArgsFunction = completeDBaaSDatabaseID
}

func completeDBaaSDatabaseID(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) < 1 {
if len(args) == 0 {
return completeDBaaSID(cmd, args, toComplete)
}
if len(args) > 1 {
return nil, cobra.ShellCompDirectiveNoFileComp
}

Expand Down
13 changes: 12 additions & 1 deletion cmd/database.dbaas.grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func init() {
dbaasGrantDeleteCmd.Flags().String("project-id", "", "Project ID (uses context if not specified)")
dbaasGrantDeleteCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
dbaasGrantDeleteCmd.Flags().Bool("dry-run", false, "Validate resource exists without deleting")

dbaasGrantCreateCmd.ValidArgsFunction = completeGrantID
dbaasGrantListCmd.ValidArgsFunction = completeGrantID
dbaasGrantGetCmd.ValidArgsFunction = completeGrantID
dbaasGrantDeleteCmd.ValidArgsFunction = completeGrantID
}

// grantRef returns a Ref for a specific grant inside a database inside a DBaaS instance.
Expand All @@ -46,7 +51,13 @@ func grantRef(projectID, dbaasID, dbName, grantID string) aruba.Ref {
}

func completeGrantID(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) < 2 {
if len(args) == 0 {
return completeDBaaSID(cmd, args, toComplete)
}
if len(args) == 1 {
return completeDBaaSDatabaseID(cmd, args, toComplete)
}
if len(args) > 2 {
return nil, cobra.ShellCompDirectiveNoFileComp
}
projectID, err := GetProjectID(cmd)
Expand Down
7 changes: 6 additions & 1 deletion cmd/database.dbaas.user.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,18 @@ func init() {
dbaasUserListCmd.Flags().Int("limit", 0, "Maximum number of results to return (0 = no limit)")
dbaasUserListCmd.Flags().Int("offset", 0, "Number of results to skip")

dbaasUserCreateCmd.ValidArgsFunction = completeDBaaSUserID
dbaasUserListCmd.ValidArgsFunction = completeDBaaSUserID
dbaasUserGetCmd.ValidArgsFunction = completeDBaaSUserID
dbaasUserUpdateCmd.ValidArgsFunction = completeDBaaSUserID
dbaasUserDeleteCmd.ValidArgsFunction = completeDBaaSUserID
}

func completeDBaaSUserID(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) < 1 {
if len(args) == 0 {
return completeDBaaSID(cmd, args, toComplete)
}
if len(args) > 1 {
return nil, cobra.ShellCompDirectiveNoFileComp
}

Expand Down
1 change: 1 addition & 0 deletions cmd/storage.backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ func init() {
storageBackupDeleteCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
storageBackupDeleteCmd.Flags().Bool("dry-run", false, "Validate resource exists without deleting")

storageBackupCmd.ValidArgsFunction = completeBlockStorageID
storageBackupGetCmd.ValidArgsFunction = completeBackupID
storageBackupUpdateCmd.ValidArgsFunction = completeBackupID
storageBackupDeleteCmd.ValidArgsFunction = completeBackupID
Expand Down
14 changes: 14 additions & 0 deletions cmd/storage.restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func init() {
storageRestoreDeleteCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt")
storageRestoreDeleteCmd.Flags().Bool("dry-run", false, "Validate resource exists without deleting")

storageRestoreCmd.ValidArgsFunction = completeStorageRestoreCreateArgs
storageRestoreGetCmd.ValidArgsFunction = completeRestoreID
storageRestoreUpdateCmd.ValidArgsFunction = completeRestoreID
storageRestoreDeleteCmd.ValidArgsFunction = completeRestoreID
Expand Down Expand Up @@ -96,6 +97,19 @@ func completeRestoreID(cmd *cobra.Command, args []string, toComplete string) ([]
return filterCompletions(completions, toComplete), cobra.ShellCompDirectiveNoFileComp
}

// completeStorageRestoreCreateArgs completes the two positional args of
// "storage restore [backup-id] [volume-id]": backup IDs at args[0], block
// storage (volume) IDs at args[1].
func completeStorageRestoreCreateArgs(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return completeBackupID(cmd, args, toComplete)
}
if len(args) == 1 {
return completeBlockStorageID(cmd, args, toComplete)
}
return nil, cobra.ShellCompDirectiveNoFileComp
}

var storageRestoreCmd = &cobra.Command{
Use: "restore [backup-id] [volume-id]",
Short: "Restore a block storage volume from a backup",
Expand Down
50 changes: 47 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,30 @@ The auto-completion system provides:
# 696c9edce63c1af07d60d0c8 BackupSnapshot
# ...

# Backups
# Backup create — completes volume ID
acloud storage backup <TAB>
# Shows:
# 6965a6c3ffc0fd1ef8ba5612 MyVolume
# ...

# Backup get/update/delete — completes backup ID
acloud storage backup get <TAB>
# Shows:
# 67649dac8c7bb1c5d7c80631 MyBackup
# 67649dac8c7bb1c5d7c80632 DailyBackup
# ...

# Restores (hierarchical: backup-id then restore-id)
# Restore create — hierarchical: backup-id then volume-id
acloud storage restore <TAB>
# First shows backup IDs:
# 67649dac8c7bb1c5d7c80631 MyBackup
# ...
acloud storage restore 67649dac8c7bb1c5d7c80631 <TAB>
# Then shows volume IDs:
# 6965a6c3ffc0fd1ef8ba5612 MyVolume
# ...

# Restore get/update/delete — hierarchical: backup-id then restore-id
acloud storage restore get <TAB>
# First shows backup IDs:
# 67649dac8c7bb1c5d7c80631 MyBackup
Expand All @@ -340,7 +356,35 @@ The auto-completion system provides:
# ...
```

Auto-completion works with `get`, `update`, and `delete` commands for all resources.
**Database Resources:**
```bash
# DBaaS database commands — hierarchical: dbaas-id then database-name
acloud database dbaas database list <TAB>
# Shows DBaaS instance IDs:
# 69455aa70d0972656501d45d my-dbaas
# ...
acloud database dbaas database get 69455aa70d0972656501d45d <TAB>
# Shows database names in that instance:
# appdb
# reporting
# ...

# DBaaS user commands — hierarchical: dbaas-id then username
acloud database dbaas user list <TAB>
# Shows DBaaS instance IDs
acloud database dbaas user get 69455aa70d0972656501d45d <TAB>
# Shows usernames in that instance

# DBaaS grant commands — hierarchical: dbaas-id, database-name, grant-id
acloud database dbaas grant list <TAB>
# Shows DBaaS instance IDs
acloud database dbaas grant list 69455aa70d0972656501d45d <TAB>
# Shows database names
acloud database dbaas grant get 69455aa70d0972656501d45d appdb <TAB>
# Shows grant IDs for that database
```

Auto-completion works with `get`, `update`, `delete`, `list`, and `create` commands for all resources.

## Verifying Installation

Expand Down
16 changes: 16 additions & 0 deletions docs/website/docs/resources/database/dbaas.database.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,22 @@ acloud database dbaas database delete <dbaas-id> <database-name> [--yes] [flags]
acloud database dbaas database delete 69455aa70d0972656501d45d "my-database" --yes
```

## Shell Auto-completion

Database commands support hierarchical auto-completion: the first TAB completes
DBaaS instance IDs, the second completes database names scoped to that instance.

```bash
# First argument — shows available DBaaS instance IDs
acloud database dbaas database list <TAB>
acloud database dbaas database get <TAB>

# Second argument — shows database names for the given DBaaS instance
acloud database dbaas database get <dbaas-id> <TAB>
acloud database dbaas database update <dbaas-id> <TAB>
acloud database dbaas database delete <dbaas-id> <TAB>
```

## Related Resources

- [DBaaS](dbaas.md) - Manage DBaaS instances
Expand Down
Loading
Loading