diff --git a/docs/stackit.md b/docs/stackit.md index 5d8cc339e..26ce39547 100644 --- a/docs/stackit.md +++ b/docs/stackit.md @@ -27,7 +27,7 @@ stackit [flags] ### SEE ALSO * [stackit argus](./stackit_argus.md) - Provides functionality for Argus -* [stackit auth](./stackit_auth.md) - Provides authentication functionality +* [stackit auth](./stackit_auth.md) - Authenticates the STACKIT CLI * [stackit config](./stackit_config.md) - Provides functionality for CLI configuration options * [stackit curl](./stackit_curl.md) - Executes an authenticated HTTP request to an endpoint * [stackit dns](./stackit_dns.md) - Provides functionality for DNS @@ -35,11 +35,11 @@ stackit [flags] * [stackit logme](./stackit_logme.md) - Provides functionality for LogMe * [stackit mariadb](./stackit_mariadb.md) - Provides functionality for MariaDB * [stackit mongodbflex](./stackit_mongodbflex.md) - Provides functionality for MongoDB Flex -* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage +* [stackit object-storage](./stackit_object-storage.md) - Provides functionality for Object Storage * [stackit opensearch](./stackit_opensearch.md) - Provides functionality for OpenSearch -* [stackit organization](./stackit_organization.md) - Provides functionality regarding organizations +* [stackit organization](./stackit_organization.md) - Manages organizations * [stackit postgresflex](./stackit_postgresflex.md) - Provides functionality for PostgreSQL Flex -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects * [stackit rabbitmq](./stackit_rabbitmq.md) - Provides functionality for RabbitMQ * [stackit redis](./stackit_redis.md) - Provides functionality for Redis * [stackit secrets-manager](./stackit_secrets-manager.md) - Provides functionality for Secrets Manager diff --git a/docs/stackit_argus_scrape-config_generate-payload.md b/docs/stackit_argus_scrape-config_generate-payload.md index 9f246dfbd..a6d725a27 100644 --- a/docs/stackit_argus_scrape-config_generate-payload.md +++ b/docs/stackit_argus_scrape-config_generate-payload.md @@ -20,19 +20,23 @@ stackit argus scrape-config generate-payload [flags] ``` Generate a Create payload with default values, and adapt it with custom values for the different configuration options - $ stackit argus scrape-config generate-payload > ./payload.json + $ stackit argus scrape-config generate-payload --file-path ./payload.json $ stackit argus scrape-config create my-config --payload @./payload.json Generate an Update payload with the values of an existing configuration named "my-config" for Argus instance xxx, and adapt it with custom values for the different configuration options - $ stackit argus scrape-config generate-payload --job-name my-config --instance-id xxx > ./payload.json + $ stackit argus scrape-config generate-payload --job-name my-config --instance-id xxx --file-path ./payload.json $ stackit argus scrape-config update my-config --payload @./payload.json + + Generate an Update payload with the values of an existing configuration named "my-config" for Argus instance xxx, and preview it in the terminal + $ stackit argus scrape-config generate-payload --job-name my-config --instance-id xxx ``` ### Options ``` + -f, --file-path string If set, writes the payload to the given file. If unset, writes the payload to the standard output -h, --help Help for "stackit argus scrape-config generate-payload" --instance-id string Instance ID -n, --job-name string If set, generates an update payload with the current state of the given scrape config. If unset, generates a create payload with default values diff --git a/docs/stackit_auth.md b/docs/stackit_auth.md index 00211ca7f..9cf637bb9 100644 --- a/docs/stackit_auth.md +++ b/docs/stackit_auth.md @@ -1,10 +1,10 @@ ## stackit auth -Provides authentication functionality +Authenticates the STACKIT CLI ### Synopsis -Provides authentication functionality. +Authenticates in the STACKIT CLI. ``` stackit auth [flags] diff --git a/docs/stackit_auth_activate-service-account.md b/docs/stackit_auth_activate-service-account.md index c7f83a103..18feefe3d 100644 --- a/docs/stackit_auth_activate-service-account.md +++ b/docs/stackit_auth_activate-service-account.md @@ -48,5 +48,5 @@ stackit auth activate-service-account [flags] ### SEE ALSO -* [stackit auth](./stackit_auth.md) - Provides authentication functionality +* [stackit auth](./stackit_auth.md) - Authenticates the STACKIT CLI diff --git a/docs/stackit_auth_login.md b/docs/stackit_auth_login.md index e1f41a63e..e839b4997 100644 --- a/docs/stackit_auth_login.md +++ b/docs/stackit_auth_login.md @@ -35,5 +35,5 @@ stackit auth login [flags] ### SEE ALSO -* [stackit auth](./stackit_auth.md) - Provides authentication functionality +* [stackit auth](./stackit_auth.md) - Authenticates the STACKIT CLI diff --git a/docs/stackit_dns_record-set.md b/docs/stackit_dns_record-set.md index 33816f70f..241199be6 100644 --- a/docs/stackit_dns_record-set.md +++ b/docs/stackit_dns_record-set.md @@ -32,6 +32,6 @@ stackit dns record-set [flags] * [stackit dns record-set create](./stackit_dns_record-set_create.md) - Creates a DNS record set * [stackit dns record-set delete](./stackit_dns_record-set_delete.md) - Deletes a DNS record set * [stackit dns record-set describe](./stackit_dns_record-set_describe.md) - Shows details of a DNS record set -* [stackit dns record-set list](./stackit_dns_record-set_list.md) - List DNS record sets +* [stackit dns record-set list](./stackit_dns_record-set_list.md) - Lists DNS record sets * [stackit dns record-set update](./stackit_dns_record-set_update.md) - Updates a DNS record set diff --git a/docs/stackit_dns_record-set_list.md b/docs/stackit_dns_record-set_list.md index 4b6e7654d..738c77f14 100644 --- a/docs/stackit_dns_record-set_list.md +++ b/docs/stackit_dns_record-set_list.md @@ -1,10 +1,10 @@ ## stackit dns record-set list -List DNS record sets +Lists DNS record sets ### Synopsis -List DNS record sets. Successfully deleted record sets are not listed by default. +Lists DNS record sets. Successfully deleted record sets are not listed by default. ``` stackit dns record-set list [flags] diff --git a/docs/stackit_dns_zone.md b/docs/stackit_dns_zone.md index 2d484e5e6..cd1bef180 100644 --- a/docs/stackit_dns_zone.md +++ b/docs/stackit_dns_zone.md @@ -32,6 +32,6 @@ stackit dns zone [flags] * [stackit dns zone create](./stackit_dns_zone_create.md) - Creates a DNS zone * [stackit dns zone delete](./stackit_dns_zone_delete.md) - Deletes a DNS zone * [stackit dns zone describe](./stackit_dns_zone_describe.md) - Shows details of a DNS zone -* [stackit dns zone list](./stackit_dns_zone_list.md) - List DNS zones +* [stackit dns zone list](./stackit_dns_zone_list.md) - Lists DNS zones * [stackit dns zone update](./stackit_dns_zone_update.md) - Updates a DNS zone diff --git a/docs/stackit_dns_zone_list.md b/docs/stackit_dns_zone_list.md index 92c527c00..099a67cf2 100644 --- a/docs/stackit_dns_zone_list.md +++ b/docs/stackit_dns_zone_list.md @@ -1,10 +1,10 @@ ## stackit dns zone list -List DNS zones +Lists DNS zones ### Synopsis -List DNS zones. Successfully deleted zones are not listed by default. +Lists DNS zones. Successfully deleted zones are not listed by default. ``` stackit dns zone list [flags] diff --git a/docs/stackit_load-balancer_generate-payload.md b/docs/stackit_load-balancer_generate-payload.md index b0533dfb2..07636cb2e 100644 --- a/docs/stackit_load-balancer_generate-payload.md +++ b/docs/stackit_load-balancer_generate-payload.md @@ -15,21 +15,25 @@ stackit load-balancer generate-payload [flags] ``` Generate a payload, and adapt it with custom values for the different configuration options - $ stackit load-balancer generate-payload > ./payload.json + $ stackit load-balancer generate-payload --file-path ./payload.json $ stackit load-balancer create --payload @./payload.json Generate a payload with values of an existing load balancer, and adapt it with custom values for the different configuration options - $ stackit load-balancer generate-payload --lb-name xxx > ./payload.json + $ stackit load-balancer generate-payload --lb-name xxx --file-path ./payload.json $ stackit load-balancer update xxx --payload @./payload.json + + Generate a payload with values of an existing load balancer, and preview it in the terminal + $ stackit load-balancer generate-payload --lb-name xxx ``` ### Options ``` - -h, --help Help for "stackit load-balancer generate-payload" - -n, --lb-name string If set, generates the payload with the current values of the given load balancer. If unset, generates the payload with empty values + -f, --file-path string If set, writes the payload to the given file. If unset, writes the payload to the standard output + -h, --help Help for "stackit load-balancer generate-payload" + -n, --lb-name string If set, generates the payload with the current values of the given load balancer. If unset, generates the payload with empty values ``` ### Options inherited from parent commands diff --git a/docs/stackit_mongodbflex_backup_restore.md b/docs/stackit_mongodbflex_backup_restore.md index 87185a3e2..18dadd1a3 100644 --- a/docs/stackit_mongodbflex_backup_restore.md +++ b/docs/stackit_mongodbflex_backup_restore.md @@ -4,8 +4,8 @@ Restores a MongoDB Flex instance from a backup ### Synopsis -Restores a MongoDB Flex instance from a backup of an instance or clones a MongoDB Flex instance from a point-in-time snapshot. -The backup is specified by a backup ID and the point-in-time snapshot is specified by a timestamp. +Restores a MongoDB Flex instance from a backup of an instance or clones a MongoDB Flex instance from a point-in-time backup. +The backup can be specified by a backup ID or a timestamp. You can specify the instance to which the backup will be applied. If not specified, the backup will be applied to the same instance from which it was taken. ``` @@ -32,7 +32,7 @@ stackit mongodbflex backup restore [flags] --backup-instance-id string Instance ID of the target instance to restore the backup to -h, --help Help for "stackit mongodbflex backup restore" --instance-id string Instance ID - --timestamp string Timestamp of the snapshot to use as a source for cloning the instance in a date-time with the RFC3339 layout format, e.g. 2024-01-01T00:00:00Z + --timestamp string Timestamp to restore the instance to, in a date-time with the RFC3339 layout format, e.g. 2024-01-01T00:00:00Z ``` ### Options inherited from parent commands diff --git a/docs/stackit_mongodbflex_backup_update-schedule.md b/docs/stackit_mongodbflex_backup_update-schedule.md index ee51091cf..872f52835 100644 --- a/docs/stackit_mongodbflex_backup_update-schedule.md +++ b/docs/stackit_mongodbflex_backup_update-schedule.md @@ -19,8 +19,8 @@ stackit mongodbflex backup update-schedule [flags] Update the backup schedule of a MongoDB Flex instance with ID "xxx" $ stackit mongodbflex backup update-schedule --instance-id xxx --schedule '6 6 * * *' - Update the retention days for snapshots of a MongoDB Flex instance with ID "xxx" to 5 days - $ stackit mongodbflex backup update-schedule --instance-id xxx --save-snapshot-days 5 + Update the retention days for backups of a MongoDB Flex instance with ID "xxx" to 5 days + $ stackit mongodbflex backup update-schedule --instance-id xxx --store-for-days 5 ``` ### Options @@ -28,11 +28,11 @@ stackit mongodbflex backup update-schedule [flags] ``` -h, --help Help for "stackit mongodbflex backup update-schedule" --instance-id string Instance ID - --save-daily-snapshot-days int Number of days to retain daily snapshots. Should be less than or equal to the number of days of the selected weekly or monthly value. - --save-monthly-snapshot-months int Number of months to retain monthly snapshots - --save-snapshot-days int Number of days to retain snapshots. Should be less than or equal to the value of the daily backup. - --save-weekly-snapshot-weeks int Number of weeks to retain weekly snapshots. Should be less than or equal to the number of weeks of the selected monthly value. --schedule string Backup schedule, in the cron scheduling system format e.g. '0 0 * * *' + --store-daily-backup-days int Number of days to retain daily backups. Should be less than or equal to the number of days of the selected weekly or monthly value. + --store-for-days int Number of days to retain backups. Should be less than or equal to the value of the daily backup. + --store-monthly-backups-months int Number of months to retain monthly backups + --store-weekly-backup-weeks int Number of weeks to retain weekly backups. Should be less than or equal to the number of weeks of the selected monthly value. ``` ### Options inherited from parent commands diff --git a/docs/stackit_object-storage.md b/docs/stackit_object-storage.md index 676bc3110..5d7def58c 100644 --- a/docs/stackit_object-storage.md +++ b/docs/stackit_object-storage.md @@ -1,10 +1,10 @@ ## stackit object-storage -Provides functionality regarding Object Storage +Provides functionality for Object Storage ### Synopsis -Provides functionality regarding Object Storage. +Provides functionality for Object Storage. ``` stackit object-storage [flags] diff --git a/docs/stackit_object-storage_bucket.md b/docs/stackit_object-storage_bucket.md index b8d8df4b6..54a2cfdf8 100644 --- a/docs/stackit_object-storage_bucket.md +++ b/docs/stackit_object-storage_bucket.md @@ -28,7 +28,7 @@ stackit object-storage bucket [flags] ### SEE ALSO -* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage +* [stackit object-storage](./stackit_object-storage.md) - Provides functionality for Object Storage * [stackit object-storage bucket create](./stackit_object-storage_bucket_create.md) - Creates an Object Storage bucket * [stackit object-storage bucket delete](./stackit_object-storage_bucket_delete.md) - Deletes an Object Storage bucket * [stackit object-storage bucket describe](./stackit_object-storage_bucket_describe.md) - Shows details of an Object Storage bucket diff --git a/docs/stackit_object-storage_credentials-group.md b/docs/stackit_object-storage_credentials-group.md index 3c028ed12..30db660a7 100644 --- a/docs/stackit_object-storage_credentials-group.md +++ b/docs/stackit_object-storage_credentials-group.md @@ -28,7 +28,7 @@ stackit object-storage credentials-group [flags] ### SEE ALSO -* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage +* [stackit object-storage](./stackit_object-storage.md) - Provides functionality for Object Storage * [stackit object-storage credentials-group create](./stackit_object-storage_credentials-group_create.md) - Creates a credentials group to hold Object Storage access credentials * [stackit object-storage credentials-group delete](./stackit_object-storage_credentials-group_delete.md) - Deletes a credentials group that holds Object Storage access credentials * [stackit object-storage credentials-group list](./stackit_object-storage_credentials-group_list.md) - Lists all credentials groups that hold Object Storage access credentials diff --git a/docs/stackit_object-storage_credentials.md b/docs/stackit_object-storage_credentials.md index de61b0195..6d602dd20 100644 --- a/docs/stackit_object-storage_credentials.md +++ b/docs/stackit_object-storage_credentials.md @@ -28,7 +28,7 @@ stackit object-storage credentials [flags] ### SEE ALSO -* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage +* [stackit object-storage](./stackit_object-storage.md) - Provides functionality for Object Storage * [stackit object-storage credentials create](./stackit_object-storage_credentials_create.md) - Creates credentials for an Object Storage credentials group * [stackit object-storage credentials delete](./stackit_object-storage_credentials_delete.md) - Deletes credentials of an Object Storage credentials group * [stackit object-storage credentials list](./stackit_object-storage_credentials_list.md) - Lists all credentials for an Object Storage credentials group diff --git a/docs/stackit_object-storage_disable.md b/docs/stackit_object-storage_disable.md index 0699e5249..e386c006f 100644 --- a/docs/stackit_object-storage_disable.md +++ b/docs/stackit_object-storage_disable.md @@ -35,5 +35,5 @@ stackit object-storage disable [flags] ### SEE ALSO -* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage +* [stackit object-storage](./stackit_object-storage.md) - Provides functionality for Object Storage diff --git a/docs/stackit_object-storage_enable.md b/docs/stackit_object-storage_enable.md index 441997bd6..6bf93bb80 100644 --- a/docs/stackit_object-storage_enable.md +++ b/docs/stackit_object-storage_enable.md @@ -35,5 +35,5 @@ stackit object-storage enable [flags] ### SEE ALSO -* [stackit object-storage](./stackit_object-storage.md) - Provides functionality regarding Object Storage +* [stackit object-storage](./stackit_object-storage.md) - Provides functionality for Object Storage diff --git a/docs/stackit_organization.md b/docs/stackit_organization.md index 2c3091969..0fefe9cb2 100644 --- a/docs/stackit_organization.md +++ b/docs/stackit_organization.md @@ -1,10 +1,10 @@ ## stackit organization -Provides functionality regarding organizations +Manages organizations ### Synopsis -Provides functionality regarding organizations. +Manages organizations. An active STACKIT organization is the root element of the resource hierarchy and a prerequisite to use any STACKIT Cloud Resource / Service. ``` @@ -30,6 +30,6 @@ stackit organization [flags] ### SEE ALSO * [stackit](./stackit.md) - Manage STACKIT resources using the command line -* [stackit organization member](./stackit_organization_member.md) - Provides functionality regarding organization members -* [stackit organization role](./stackit_organization_role.md) - Provides functionality regarding organization roles +* [stackit organization member](./stackit_organization_member.md) - Manages organization members +* [stackit organization role](./stackit_organization_role.md) - Manages organization roles diff --git a/docs/stackit_organization_member.md b/docs/stackit_organization_member.md index e7651ee04..496aa4466 100644 --- a/docs/stackit_organization_member.md +++ b/docs/stackit_organization_member.md @@ -1,10 +1,10 @@ ## stackit organization member -Provides functionality regarding organization members +Manages organization members ### Synopsis -Provides functionality regarding organization members. +Manages organization members. ``` stackit organization member [flags] @@ -28,7 +28,7 @@ stackit organization member [flags] ### SEE ALSO -* [stackit organization](./stackit_organization.md) - Provides functionality regarding organizations +* [stackit organization](./stackit_organization.md) - Manages organizations * [stackit organization member add](./stackit_organization_member_add.md) - Adds a member to an organization * [stackit organization member list](./stackit_organization_member_list.md) - Lists members of an organization * [stackit organization member remove](./stackit_organization_member_remove.md) - Removes a member from an organization diff --git a/docs/stackit_organization_member_add.md b/docs/stackit_organization_member_add.md index 46f7dedf0..0e5a50491 100644 --- a/docs/stackit_organization_member_add.md +++ b/docs/stackit_organization_member_add.md @@ -41,5 +41,5 @@ stackit organization member add SUBJECT [flags] ### SEE ALSO -* [stackit organization member](./stackit_organization_member.md) - Provides functionality regarding organization members +* [stackit organization member](./stackit_organization_member.md) - Manages organization members diff --git a/docs/stackit_organization_member_list.md b/docs/stackit_organization_member_list.md index 2f3772038..2263ce2a4 100644 --- a/docs/stackit_organization_member_list.md +++ b/docs/stackit_organization_member_list.md @@ -45,5 +45,5 @@ stackit organization member list [flags] ### SEE ALSO -* [stackit organization member](./stackit_organization_member.md) - Provides functionality regarding organization members +* [stackit organization member](./stackit_organization_member.md) - Manages organization members diff --git a/docs/stackit_organization_member_remove.md b/docs/stackit_organization_member_remove.md index f164052b8..8c425a22c 100644 --- a/docs/stackit_organization_member_remove.md +++ b/docs/stackit_organization_member_remove.md @@ -43,5 +43,5 @@ stackit organization member remove SUBJECT [flags] ### SEE ALSO -* [stackit organization member](./stackit_organization_member.md) - Provides functionality regarding organization members +* [stackit organization member](./stackit_organization_member.md) - Manages organization members diff --git a/docs/stackit_organization_role.md b/docs/stackit_organization_role.md index e95f20a39..2a5d2f75a 100644 --- a/docs/stackit_organization_role.md +++ b/docs/stackit_organization_role.md @@ -1,10 +1,10 @@ ## stackit organization role -Provides functionality regarding organization roles +Manages organization roles ### Synopsis -Provides functionality regarding organization roles. +Manages organization roles. ``` stackit organization role [flags] @@ -28,6 +28,6 @@ stackit organization role [flags] ### SEE ALSO -* [stackit organization](./stackit_organization.md) - Provides functionality regarding organizations +* [stackit organization](./stackit_organization.md) - Manages organizations * [stackit organization role list](./stackit_organization_role_list.md) - Lists roles and permissions of an organization diff --git a/docs/stackit_organization_role_list.md b/docs/stackit_organization_role_list.md index 9f2f9b491..0228eca5c 100644 --- a/docs/stackit_organization_role_list.md +++ b/docs/stackit_organization_role_list.md @@ -43,5 +43,5 @@ stackit organization role list [flags] ### SEE ALSO -* [stackit organization role](./stackit_organization_role.md) - Provides functionality regarding organization roles +* [stackit organization role](./stackit_organization_role.md) - Manages organization roles diff --git a/docs/stackit_project.md b/docs/stackit_project.md index 5c30842c4..7f002da38 100644 --- a/docs/stackit_project.md +++ b/docs/stackit_project.md @@ -1,10 +1,10 @@ ## stackit project -Provides functionality regarding projects +Manages projects ### Synopsis -Provides functionality regarding projects. +Provides functionality for projects. A project is a container for resources which is the service that you can purchase from STACKIT. ``` @@ -34,7 +34,7 @@ stackit project [flags] * [stackit project delete](./stackit_project_delete.md) - Deletes a STACKIT project * [stackit project describe](./stackit_project_describe.md) - Shows details of a STACKIT project * [stackit project list](./stackit_project_list.md) - Lists STACKIT projects -* [stackit project member](./stackit_project_member.md) - Provides functionality regarding project members -* [stackit project role](./stackit_project_role.md) - Provides functionality regarding project roles +* [stackit project member](./stackit_project_member.md) - Manages project members +* [stackit project role](./stackit_project_role.md) - Manages project roles * [stackit project update](./stackit_project_update.md) - Updates a STACKIT project diff --git a/docs/stackit_project_create.md b/docs/stackit_project_create.md index b3168ab91..ae6e22723 100644 --- a/docs/stackit_project_create.md +++ b/docs/stackit_project_create.md @@ -41,5 +41,5 @@ stackit project create [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects diff --git a/docs/stackit_project_delete.md b/docs/stackit_project_delete.md index 03566109f..66b60ed00 100644 --- a/docs/stackit_project_delete.md +++ b/docs/stackit_project_delete.md @@ -38,5 +38,5 @@ stackit project delete [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects diff --git a/docs/stackit_project_describe.md b/docs/stackit_project_describe.md index 24f145174..a3976ece6 100644 --- a/docs/stackit_project_describe.md +++ b/docs/stackit_project_describe.md @@ -42,5 +42,5 @@ stackit project describe [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects diff --git a/docs/stackit_project_list.md b/docs/stackit_project_list.md index c968bef0c..28aa2693b 100644 --- a/docs/stackit_project_list.md +++ b/docs/stackit_project_list.md @@ -50,5 +50,5 @@ stackit project list [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects diff --git a/docs/stackit_project_member.md b/docs/stackit_project_member.md index 6cf65e449..c2021638a 100644 --- a/docs/stackit_project_member.md +++ b/docs/stackit_project_member.md @@ -1,10 +1,10 @@ ## stackit project member -Provides functionality regarding project members +Manages project members ### Synopsis -Provides functionality regarding project members. +Manages project members. ``` stackit project member [flags] @@ -28,7 +28,7 @@ stackit project member [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects * [stackit project member add](./stackit_project_member_add.md) - Adds a member to a project * [stackit project member list](./stackit_project_member_list.md) - Lists members of a project * [stackit project member remove](./stackit_project_member_remove.md) - Removes a member from a project diff --git a/docs/stackit_project_member_add.md b/docs/stackit_project_member_add.md index b92c1d1e0..105676243 100644 --- a/docs/stackit_project_member_add.md +++ b/docs/stackit_project_member_add.md @@ -40,5 +40,5 @@ stackit project member add SUBJECT [flags] ### SEE ALSO -* [stackit project member](./stackit_project_member.md) - Provides functionality regarding project members +* [stackit project member](./stackit_project_member.md) - Manages project members diff --git a/docs/stackit_project_member_list.md b/docs/stackit_project_member_list.md index dbc1b5f06..c27436336 100644 --- a/docs/stackit_project_member_list.md +++ b/docs/stackit_project_member_list.md @@ -44,5 +44,5 @@ stackit project member list [flags] ### SEE ALSO -* [stackit project member](./stackit_project_member.md) - Provides functionality regarding project members +* [stackit project member](./stackit_project_member.md) - Manages project members diff --git a/docs/stackit_project_member_remove.md b/docs/stackit_project_member_remove.md index f94e96a04..9c9e46ffe 100644 --- a/docs/stackit_project_member_remove.md +++ b/docs/stackit_project_member_remove.md @@ -42,5 +42,5 @@ stackit project member remove SUBJECT [flags] ### SEE ALSO -* [stackit project member](./stackit_project_member.md) - Provides functionality regarding project members +* [stackit project member](./stackit_project_member.md) - Manages project members diff --git a/docs/stackit_project_role.md b/docs/stackit_project_role.md index 17551b60d..b95577866 100644 --- a/docs/stackit_project_role.md +++ b/docs/stackit_project_role.md @@ -1,10 +1,10 @@ ## stackit project role -Provides functionality regarding project roles +Manages project roles ### Synopsis -Provides functionality regarding project roles. +Manages project roles. ``` stackit project role [flags] @@ -28,6 +28,6 @@ stackit project role [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects * [stackit project role list](./stackit_project_role_list.md) - Lists roles and permissions of a project diff --git a/docs/stackit_project_role_list.md b/docs/stackit_project_role_list.md index 2c34a8727..6744c4c8c 100644 --- a/docs/stackit_project_role_list.md +++ b/docs/stackit_project_role_list.md @@ -42,5 +42,5 @@ stackit project role list [flags] ### SEE ALSO -* [stackit project role](./stackit_project_role.md) - Provides functionality regarding project roles +* [stackit project role](./stackit_project_role.md) - Manages project roles diff --git a/docs/stackit_project_update.md b/docs/stackit_project_update.md index f9e569c8a..b057276be 100644 --- a/docs/stackit_project_update.md +++ b/docs/stackit_project_update.md @@ -44,5 +44,5 @@ stackit project update [flags] ### SEE ALSO -* [stackit project](./stackit_project.md) - Provides functionality regarding projects +* [stackit project](./stackit_project.md) - Manages projects diff --git a/docs/stackit_service-account.md b/docs/stackit_service-account.md index c2fed18c5..4d72ed5e7 100644 --- a/docs/stackit_service-account.md +++ b/docs/stackit_service-account.md @@ -32,7 +32,7 @@ stackit service-account [flags] * [stackit service-account create](./stackit_service-account_create.md) - Creates a service account * [stackit service-account delete](./stackit_service-account_delete.md) - Deletes a service account * [stackit service-account get-jwks](./stackit_service-account_get-jwks.md) - Shows the JWKS for a service account -* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality regarding service account keys +* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality for service account keys * [stackit service-account list](./stackit_service-account_list.md) - Lists all service accounts -* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality regarding service account tokens +* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality for service account tokens diff --git a/docs/stackit_service-account_key.md b/docs/stackit_service-account_key.md index 40b9c8c26..ad9ad8aae 100644 --- a/docs/stackit_service-account_key.md +++ b/docs/stackit_service-account_key.md @@ -1,10 +1,10 @@ ## stackit service-account key -Provides functionality regarding service account keys +Provides functionality for service account keys ### Synopsis -Provides functionality regarding service account keys. +Provides functionality for service account keys. ``` stackit service-account key [flags] diff --git a/docs/stackit_service-account_key_create.md b/docs/stackit_service-account_key_create.md index 0e33bd90a..0f50cf0df 100644 --- a/docs/stackit_service-account_key_create.md +++ b/docs/stackit_service-account_key_create.md @@ -46,5 +46,5 @@ stackit service-account key create [flags] ### SEE ALSO -* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality regarding service account keys +* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality for service account keys diff --git a/docs/stackit_service-account_key_delete.md b/docs/stackit_service-account_key_delete.md index c882dc490..aa28e8413 100644 --- a/docs/stackit_service-account_key_delete.md +++ b/docs/stackit_service-account_key_delete.md @@ -36,5 +36,5 @@ stackit service-account key delete KEY_ID [flags] ### SEE ALSO -* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality regarding service account keys +* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality for service account keys diff --git a/docs/stackit_service-account_key_describe.md b/docs/stackit_service-account_key_describe.md index 21f949d79..58a3b922d 100644 --- a/docs/stackit_service-account_key_describe.md +++ b/docs/stackit_service-account_key_describe.md @@ -36,5 +36,5 @@ stackit service-account key describe KEY_ID [flags] ### SEE ALSO -* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality regarding service account keys +* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality for service account keys diff --git a/docs/stackit_service-account_key_list.md b/docs/stackit_service-account_key_list.md index c141676ac..811f40454 100644 --- a/docs/stackit_service-account_key_list.md +++ b/docs/stackit_service-account_key_list.md @@ -43,5 +43,5 @@ stackit service-account key list [flags] ### SEE ALSO -* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality regarding service account keys +* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality for service account keys diff --git a/docs/stackit_service-account_key_update.md b/docs/stackit_service-account_key_update.md index 2c8e2f751..31ec346d6 100644 --- a/docs/stackit_service-account_key_update.md +++ b/docs/stackit_service-account_key_update.md @@ -46,5 +46,5 @@ stackit service-account key update KEY_ID [flags] ### SEE ALSO -* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality regarding service account keys +* [stackit service-account key](./stackit_service-account_key.md) - Provides functionality for service account keys diff --git a/docs/stackit_service-account_token.md b/docs/stackit_service-account_token.md index 03888a32c..7a3a5e066 100644 --- a/docs/stackit_service-account_token.md +++ b/docs/stackit_service-account_token.md @@ -1,10 +1,10 @@ ## stackit service-account token -Provides functionality regarding service account tokens +Provides functionality for service account tokens ### Synopsis -Provides functionality regarding service account tokens. +Provides functionality for service account tokens. ``` stackit service-account token [flags] diff --git a/docs/stackit_service-account_token_create.md b/docs/stackit_service-account_token_create.md index ebca082ca..49797b420 100644 --- a/docs/stackit_service-account_token_create.md +++ b/docs/stackit_service-account_token_create.md @@ -42,5 +42,5 @@ stackit service-account token create [flags] ### SEE ALSO -* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality regarding service account tokens +* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality for service account tokens diff --git a/docs/stackit_service-account_token_list.md b/docs/stackit_service-account_token_list.md index daaa3d06d..e340adadb 100644 --- a/docs/stackit_service-account_token_list.md +++ b/docs/stackit_service-account_token_list.md @@ -45,5 +45,5 @@ stackit service-account token list [flags] ### SEE ALSO -* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality regarding service account tokens +* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality for service account tokens diff --git a/docs/stackit_service-account_token_revoke.md b/docs/stackit_service-account_token_revoke.md index 57c73899f..42a2f5fbb 100644 --- a/docs/stackit_service-account_token_revoke.md +++ b/docs/stackit_service-account_token_revoke.md @@ -38,5 +38,5 @@ stackit service-account token revoke TOKEN_ID [flags] ### SEE ALSO -* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality regarding service account tokens +* [stackit service-account token](./stackit_service-account_token.md) - Provides functionality for service account tokens diff --git a/docs/stackit_ske_cluster_generate-payload.md b/docs/stackit_ske_cluster_generate-payload.md index dc07bfa22..9a40bb105 100644 --- a/docs/stackit_ske_cluster_generate-payload.md +++ b/docs/stackit_ske_cluster_generate-payload.md @@ -15,20 +15,24 @@ stackit ske cluster generate-payload [flags] ``` Generate a payload with default values, and adapt it with custom values for the different configuration options - $ stackit ske cluster generate-payload > ./payload.json + $ stackit ske cluster generate-payload --file-path ./payload.json $ stackit ske cluster create my-cluster --payload @./payload.json Generate a payload with values of a cluster, and adapt it with custom values for the different configuration options - $ stackit ske cluster generate-payload --cluster-name my-cluster > ./payload.json + $ stackit ske cluster generate-payload --cluster-name my-cluster --file-path ./payload.json $ stackit ske cluster update my-cluster --payload @./payload.json + + Generate a payload with values of a cluster, and preview it in the terminal + $ stackit ske cluster generate-payload --cluster-name my-cluster ``` ### Options ``` -n, --cluster-name string If set, generates the payload with the current state of the given cluster. If unset, generates the payload with default values + -f, --file-path string If set, writes the payload to the given file. If unset, writes the payload to the standard output -h, --help Help for "stackit ske cluster generate-payload" ``` diff --git a/internal/cmd/argus/scrape-config/generate-payload/generate_payload.go b/internal/cmd/argus/scrape-config/generate-payload/generate_payload.go index 310ac67f3..9d5e720f2 100644 --- a/internal/cmd/argus/scrape-config/generate-payload/generate_payload.go +++ b/internal/cmd/argus/scrape-config/generate-payload/generate_payload.go @@ -7,6 +7,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/args" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/fileutils" "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" @@ -20,12 +21,14 @@ import ( const ( jobNameFlag = "job-name" instanceIdFlag = "instance-id" + filePathFlag = "file-path" ) type inputModel struct { *globalflags.GlobalFlagModel JobName *string InstanceId string + FilePath *string } func NewCmd(p *print.Printer) *cobra.Command { @@ -44,14 +47,17 @@ func NewCmd(p *print.Printer) *cobra.Command { Example: examples.Build( examples.NewExample( `Generate a Create payload with default values, and adapt it with custom values for the different configuration options`, - `$ stackit argus scrape-config generate-payload > ./payload.json`, + `$ stackit argus scrape-config generate-payload --file-path ./payload.json`, ``, `$ stackit argus scrape-config create my-config --payload @./payload.json`), examples.NewExample( `Generate an Update payload with the values of an existing configuration named "my-config" for Argus instance xxx, and adapt it with custom values for the different configuration options`, - `$ stackit argus scrape-config generate-payload --job-name my-config --instance-id xxx > ./payload.json`, + `$ stackit argus scrape-config generate-payload --job-name my-config --instance-id xxx --file-path ./payload.json`, ``, `$ stackit argus scrape-config update my-config --payload @./payload.json`), + examples.NewExample( + `Generate an Update payload with the values of an existing configuration named "my-config" for Argus instance xxx, and preview it in the terminal`, + `$ stackit argus scrape-config generate-payload --job-name my-config --instance-id xxx`), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -68,7 +74,7 @@ func NewCmd(p *print.Printer) *cobra.Command { if model.JobName == nil { createPayload := argusUtils.DefaultCreateScrapeConfigPayload - return outputCreateResult(p, &createPayload) + return outputCreateResult(p, model.FilePath, &createPayload) } req := buildRequest(ctx, model, apiClient) @@ -82,7 +88,7 @@ func NewCmd(p *print.Printer) *cobra.Command { return fmt.Errorf("map update scrape config payloads: %w", err) } - return outputUpdateResult(p, payload) + return outputUpdateResult(p, model.FilePath, payload) }, } configureFlags(cmd) @@ -92,6 +98,7 @@ func NewCmd(p *print.Printer) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().Var(flags.UUIDFlag(), instanceIdFlag, "Instance ID") cmd.Flags().StringP(jobNameFlag, "n", "", "If set, generates an update payload with the current state of the given scrape config. If unset, generates a create payload with default values") + cmd.Flags().StringP(filePathFlag, "f", "", "If set, writes the payload to the given file. If unset, writes the payload to the standard output") } func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { @@ -108,6 +115,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { GlobalFlagModel: globalFlags, JobName: jobName, InstanceId: flags.FlagToStringValue(p, cmd, instanceIdFlag), + FilePath: flags.FlagToStringPointer(p, cmd, filePathFlag), }, nil } @@ -116,22 +124,38 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *argus.APICl return req } -func outputCreateResult(p *print.Printer, payload *argus.CreateScrapeConfigPayload) error { +func outputCreateResult(p *print.Printer, filePath *string, payload *argus.CreateScrapeConfigPayload) error { payloadBytes, err := json.MarshalIndent(*payload, "", " ") if err != nil { return fmt.Errorf("marshal payload: %w", err) } - p.Outputln(string(payloadBytes)) + + if filePath != nil { + err = fileutils.WriteToFile(*filePath, string(payloadBytes)) + if err != nil { + return fmt.Errorf("write payload to the file: %w", err) + } + } else { + p.Outputln(string(payloadBytes)) + } return nil } -func outputUpdateResult(p *print.Printer, payload *argus.UpdateScrapeConfigPayload) error { +func outputUpdateResult(p *print.Printer, filePath *string, payload *argus.UpdateScrapeConfigPayload) error { payloadBytes, err := json.MarshalIndent(*payload, "", " ") if err != nil { return fmt.Errorf("marshal payload: %w", err) } - p.Outputln(string(payloadBytes)) + + if filePath != nil { + err = fileutils.WriteToFile(*filePath, string(payloadBytes)) + if err != nil { + return fmt.Errorf("write payload to the file: %w", err) + } + } else { + p.Outputln(string(payloadBytes)) + } return nil } diff --git a/internal/cmd/argus/scrape-config/generate-payload/generate_payload_test.go b/internal/cmd/argus/scrape-config/generate-payload/generate_payload_test.go index 3c1fafd38..5c04abd5c 100644 --- a/internal/cmd/argus/scrape-config/generate-payload/generate_payload_test.go +++ b/internal/cmd/argus/scrape-config/generate-payload/generate_payload_test.go @@ -22,13 +22,17 @@ var testClient = &argus.APIClient{} var testProjectId = uuid.NewString() var testInstanceId = uuid.NewString() -const testJobName = "test-job-name" +const ( + testJobName = "test-job-name" + testFilePath = "example-file" +) func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ projectIdFlag: testProjectId, instanceIdFlag: testInstanceId, jobNameFlag: testJobName, + filePathFlag: testFilePath, } for _, mod := range mods { mod(flagValues) @@ -44,6 +48,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { }, InstanceId: testInstanceId, JobName: utils.Ptr(testJobName), + FilePath: utils.Ptr(testFilePath), } for _, mod := range mods { mod(model) @@ -80,6 +85,16 @@ func TestParseInput(t *testing.T) { GlobalFlagModel: &globalflags.GlobalFlagModel{Verbosity: globalflags.VerbosityDefault}, }, }, + { + description: "file path missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, filePathFlag) + }), + isValid: true, + expectedModel: fixtureInputModel(func(model *inputModel) { + model.FilePath = nil + }), + }, { description: "job name missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { diff --git a/internal/cmd/auth/activate-service-account/activate_service_account_test.go b/internal/cmd/auth/activate-service-account/activate_service_account_test.go index 5b0799a58..a9e12b30c 100644 --- a/internal/cmd/auth/activate-service-account/activate_service_account_test.go +++ b/internal/cmd/auth/activate-service-account/activate_service_account_test.go @@ -3,8 +3,10 @@ package activateserviceaccount import ( "testing" + "github.com/stackitcloud/stackit-cli/internal/pkg/auth" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/zalando/go-keyring" "github.com/google/go-cmp/cmp" ) @@ -120,3 +122,62 @@ func TestParseInput(t *testing.T) { }) } } + +func TestStoreFlags(t *testing.T) { + tests := []struct { + description string + model *inputModel + isValid bool + }{ + { + description: "base", + model: fixtureInputModel(), + isValid: true, + }, + { + description: "no values", + model: &inputModel{ + ServiceAccountToken: "", + ServiceAccountKeyPath: "", + PrivateKeyPath: "", + TokenCustomEndpoint: "", + JwksCustomEndpoint: "", + }, + isValid: true, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + // Initialize an empty keyring + keyring.MockInit() + + err := storeFlags(tt.model) + if !tt.isValid { + if err == nil { + t.Fatalf("did not fail on invalid input") + } + return + } + if err != nil { + t.Fatalf("store flags: %v", err) + } + + value, err := auth.GetAuthField(auth.TOKEN_CUSTOM_ENDPOINT) + if err != nil { + t.Errorf("Failed to get value of auth field: %v", err) + } + if value != tt.model.TokenCustomEndpoint { + t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.TOKEN_CUSTOM_ENDPOINT, tt.model.TokenCustomEndpoint, value) + } + + value, err = auth.GetAuthField(auth.JWKS_CUSTOM_ENDPOINT) + if err != nil { + t.Errorf("Failed to get value of auth field: %v", err) + } + if value != tt.model.JwksCustomEndpoint { + t.Errorf("Value of \"%s\" does not match: expected \"%s\", got \"%s\"", auth.JWKS_CUSTOM_ENDPOINT, tt.model.TokenCustomEndpoint, value) + } + }) + } +} diff --git a/internal/cmd/auth/auth.go b/internal/cmd/auth/auth.go index cad07aaed..061e5e85e 100644 --- a/internal/cmd/auth/auth.go +++ b/internal/cmd/auth/auth.go @@ -13,8 +13,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "auth", - Short: "Provides authentication functionality", - Long: "Provides authentication functionality.", + Short: "Authenticates the STACKIT CLI", + Long: "Authenticates in the STACKIT CLI.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/dns/record-set/list/list.go b/internal/cmd/dns/record-set/list/list.go index a3a842832..40edbcbec 100644 --- a/internal/cmd/dns/record-set/list/list.go +++ b/internal/cmd/dns/record-set/list/list.go @@ -51,8 +51,8 @@ type inputModel struct { func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "list", - Short: "List DNS record sets", - Long: `List DNS record sets. Successfully deleted record sets are not listed by default.`, + Short: "Lists DNS record sets", + Long: `Lists DNS record sets. Successfully deleted record sets are not listed by default.`, Args: args.NoArgs, Example: examples.Build( examples.NewExample( diff --git a/internal/cmd/dns/zone/list/list.go b/internal/cmd/dns/zone/list/list.go index 49e23a0b0..46d08b31c 100644 --- a/internal/cmd/dns/zone/list/list.go +++ b/internal/cmd/dns/zone/list/list.go @@ -49,8 +49,8 @@ type inputModel struct { func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "list", - Short: "List DNS zones", - Long: `List DNS zones. Successfully deleted zones are not listed by default.`, + Short: "Lists DNS zones", + Long: `Lists DNS zones. Successfully deleted zones are not listed by default.`, Args: args.NoArgs, Example: examples.Build( examples.NewExample( diff --git a/internal/cmd/load-balancer/generate-payload/generate_payload.go b/internal/cmd/load-balancer/generate-payload/generate_payload.go index 6275ba819..4d560fc42 100644 --- a/internal/cmd/load-balancer/generate-payload/generate_payload.go +++ b/internal/cmd/load-balancer/generate-payload/generate_payload.go @@ -8,6 +8,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/args" "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/fileutils" "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" @@ -20,11 +21,13 @@ import ( const ( loadBalancerNameFlag = "lb-name" + filePathFlag = "file-path" ) type inputModel struct { *globalflags.GlobalFlagModel LoadBalancerName *string + FilePath *string } var ( @@ -118,14 +121,17 @@ func NewCmd(p *print.Printer) *cobra.Command { Example: examples.Build( examples.NewExample( `Generate a payload, and adapt it with custom values for the different configuration options`, - `$ stackit load-balancer generate-payload > ./payload.json`, + `$ stackit load-balancer generate-payload --file-path ./payload.json`, ``, `$ stackit load-balancer create --payload @./payload.json`), examples.NewExample( `Generate a payload with values of an existing load balancer, and adapt it with custom values for the different configuration options`, - `$ stackit load-balancer generate-payload --lb-name xxx > ./payload.json`, + `$ stackit load-balancer generate-payload --lb-name xxx --file-path ./payload.json`, ``, `$ stackit load-balancer update xxx --payload @./payload.json`), + examples.NewExample( + `Generate a payload with values of an existing load balancer, and preview it in the terminal`, + `$ stackit load-balancer generate-payload --lb-name xxx`), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -142,7 +148,7 @@ func NewCmd(p *print.Printer) *cobra.Command { if model.LoadBalancerName == nil { createPayload := DefaultCreateLoadBalancerPayload - return outputCreateResult(p, &createPayload) + return outputCreateResult(p, model.FilePath, &createPayload) } req := buildRequest(ctx, model, apiClient) @@ -162,7 +168,7 @@ func NewCmd(p *print.Printer) *cobra.Command { TargetPools: resp.TargetPools, Version: resp.Version, } - return outputUpdateResult(p, updatePayload) + return outputUpdateResult(p, model.FilePath, updatePayload) }, } configureFlags(cmd) @@ -171,6 +177,7 @@ func NewCmd(p *print.Printer) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().StringP(loadBalancerNameFlag, "n", "", "If set, generates the payload with the current values of the given load balancer. If unset, generates the payload with empty values") + cmd.Flags().StringP(filePathFlag, "f", "", "If set, writes the payload to the given file. If unset, writes the payload to the standard output") } func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { @@ -185,6 +192,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { model := inputModel{ GlobalFlagModel: globalFlags, LoadBalancerName: loadBalancerName, + FilePath: flags.FlagToStringPointer(p, cmd, filePathFlag), } if p.IsVerbosityDebug() { @@ -204,22 +212,38 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *loadbalance return req } -func outputCreateResult(p *print.Printer, payload *loadbalancer.CreateLoadBalancerPayload) error { +func outputCreateResult(p *print.Printer, filePath *string, payload *loadbalancer.CreateLoadBalancerPayload) error { payloadBytes, err := json.MarshalIndent(*payload, "", " ") if err != nil { return fmt.Errorf("marshal create load balancer payload: %w", err) } - p.Outputln(string(payloadBytes)) + + if filePath != nil { + err = fileutils.WriteToFile(*filePath, string(payloadBytes)) + if err != nil { + return fmt.Errorf("write create load balancer payload to the file: %w", err) + } + } else { + p.Outputln(string(payloadBytes)) + } return nil } -func outputUpdateResult(p *print.Printer, payload *loadbalancer.UpdateLoadBalancerPayload) error { +func outputUpdateResult(p *print.Printer, filePath *string, payload *loadbalancer.UpdateLoadBalancerPayload) error { payloadBytes, err := json.MarshalIndent(*payload, "", " ") if err != nil { return fmt.Errorf("marshal update load balancer payload: %w", err) } - p.Outputln(string(payloadBytes)) + + if filePath != nil { + err = fileutils.WriteToFile(*filePath, string(payloadBytes)) + if err != nil { + return fmt.Errorf("write update load balancer payload to the file: %w", err) + } + } else { + p.Outputln(string(payloadBytes)) + } return nil } diff --git a/internal/cmd/load-balancer/generate-payload/generate_payload_test.go b/internal/cmd/load-balancer/generate-payload/generate_payload_test.go index a1661d545..b8f48fc69 100644 --- a/internal/cmd/load-balancer/generate-payload/generate_payload_test.go +++ b/internal/cmd/load-balancer/generate-payload/generate_payload_test.go @@ -23,10 +23,16 @@ var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &loadbalancer.APIClient{} var testProjectId = uuid.NewString() +const ( + testLoadBalancerName = "example-name" + testFilePath = "example-file" +) + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ projectIdFlag: testProjectId, - loadBalancerNameFlag: "example-name", + loadBalancerNameFlag: testLoadBalancerName, + filePathFlag: testFilePath, } for _, mod := range mods { mod(flagValues) @@ -40,7 +46,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, }, - LoadBalancerName: utils.Ptr("example-name"), + LoadBalancerName: utils.Ptr(testLoadBalancerName), + FilePath: utils.Ptr(testFilePath), } for _, mod := range mods { mod(model) @@ -49,7 +56,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *loadbalancer.ApiGetLoadBalancerRequest)) loadbalancer.ApiGetLoadBalancerRequest { - request := testClient.GetLoadBalancer(testCtx, testProjectId, "example-name") + request := testClient.GetLoadBalancer(testCtx, testProjectId, testLoadBalancerName) for _, mod := range mods { mod(&request) } @@ -87,6 +94,16 @@ func TestParseInput(t *testing.T) { model.LoadBalancerName = nil }), }, + { + description: "file path missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, filePathFlag) + }), + isValid: true, + expectedModel: fixtureInputModel(func(model *inputModel) { + model.FilePath = nil + }), + }, { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { diff --git a/internal/cmd/mongodbflex/backup/restore/restore.go b/internal/cmd/mongodbflex/backup/restore/restore.go index c043e4292..d74611db3 100644 --- a/internal/cmd/mongodbflex/backup/restore/restore.go +++ b/internal/cmd/mongodbflex/backup/restore/restore.go @@ -39,8 +39,8 @@ func NewCmd(p *print.Printer) *cobra.Command { Use: "restore", Short: "Restores a MongoDB Flex instance from a backup", Long: fmt.Sprintf("%s\n%s\n%s", - "Restores a MongoDB Flex instance from a backup of an instance or clones a MongoDB Flex instance from a point-in-time snapshot.", - "The backup is specified by a backup ID and the point-in-time snapshot is specified by a timestamp.", + "Restores a MongoDB Flex instance from a backup of an instance or clones a MongoDB Flex instance from a point-in-time backup.", + "The backup can be specified by a backup ID or a timestamp.", "You can specify the instance to which the backup will be applied. If not specified, the backup will be applied to the same instance from which it was taken.", ), Args: args.NoArgs, @@ -141,7 +141,7 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Var(flags.UUIDFlag(), instanceIdFlag, "Instance ID") cmd.Flags().Var(flags.UUIDFlag(), backupInstanceIdFlag, "Instance ID of the target instance to restore the backup to") cmd.Flags().String(backupIdFlag, "", "Backup ID") - cmd.Flags().String(timestampFlag, "", "Timestamp of the snapshot to use as a source for cloning the instance in a date-time with the RFC3339 layout format, e.g. 2024-01-01T00:00:00Z") + cmd.Flags().String(timestampFlag, "", "Timestamp to restore the instance to, in a date-time with the RFC3339 layout format, e.g. 2024-01-01T00:00:00Z") err := flags.MarkFlagsRequired(cmd, instanceIdFlag) cobra.CheckErr(err) diff --git a/internal/cmd/mongodbflex/backup/update-schedule/update_schedule.go b/internal/cmd/mongodbflex/backup/update-schedule/update_schedule.go index cf296ea92..5b2f71bba 100644 --- a/internal/cmd/mongodbflex/backup/update-schedule/update_schedule.go +++ b/internal/cmd/mongodbflex/backup/update-schedule/update_schedule.go @@ -21,10 +21,10 @@ import ( const ( instanceIdFlag = "instance-id" scheduleFlag = "schedule" - snapshotRetentionDaysFlag = "save-snapshot-days" - dailySnapshotRetentionDaysFlag = "save-daily-snapshot-days" - weeklySnapshotRetentionWeeksFlag = "save-weekly-snapshot-weeks" - monthlySnapshotRetentionMonthsFlag = "save-monthly-snapshot-months" + snapshotRetentionDaysFlag = "store-for-days" + dailySnapshotRetentionDaysFlag = "store-daily-backup-days" + weeklySnapshotRetentionWeeksFlag = "store-weekly-backup-weeks" + monthlySnapshotRetentionMonthsFlag = "store-monthly-backups-months" // Default values for the backup schedule options defaultBackupSchedule = "0 0/6 * * *" @@ -62,8 +62,8 @@ func NewCmd(p *print.Printer) *cobra.Command { `Update the backup schedule of a MongoDB Flex instance with ID "xxx"`, "$ stackit mongodbflex backup update-schedule --instance-id xxx --schedule '6 6 * * *'"), examples.NewExample( - `Update the retention days for snapshots of a MongoDB Flex instance with ID "xxx" to 5 days`, - "$ stackit mongodbflex backup update-schedule --instance-id xxx --save-snapshot-days 5"), + `Update the retention days for backups of a MongoDB Flex instance with ID "xxx" to 5 days`, + "$ stackit mongodbflex backup update-schedule --instance-id xxx --store-for-days 5"), ), RunE: func(cmd *cobra.Command, args []string) error { @@ -121,10 +121,10 @@ func NewCmd(p *print.Printer) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().Var(flags.UUIDFlag(), instanceIdFlag, "Instance ID") cmd.Flags().String(scheduleFlag, "", "Backup schedule, in the cron scheduling system format e.g. '0 0 * * *'") - cmd.Flags().Int64(snapshotRetentionDaysFlag, 0, "Number of days to retain snapshots. Should be less than or equal to the value of the daily backup.") - cmd.Flags().Int64(dailySnapshotRetentionDaysFlag, 0, "Number of days to retain daily snapshots. Should be less than or equal to the number of days of the selected weekly or monthly value.") - cmd.Flags().Int64(weeklySnapshotRetentionWeeksFlag, 0, "Number of weeks to retain weekly snapshots. Should be less than or equal to the number of weeks of the selected monthly value.") - cmd.Flags().Int64(monthlySnapshotRetentionMonthsFlag, 0, "Number of months to retain monthly snapshots") + cmd.Flags().Int64(snapshotRetentionDaysFlag, 0, "Number of days to retain backups. Should be less than or equal to the value of the daily backup.") + cmd.Flags().Int64(dailySnapshotRetentionDaysFlag, 0, "Number of days to retain daily backups. Should be less than or equal to the number of days of the selected weekly or monthly value.") + cmd.Flags().Int64(weeklySnapshotRetentionWeeksFlag, 0, "Number of weeks to retain weekly backups. Should be less than or equal to the number of weeks of the selected monthly value.") + cmd.Flags().Int64(monthlySnapshotRetentionMonthsFlag, 0, "Number of months to retain monthly backups") err := flags.MarkFlagsRequired(cmd, instanceIdFlag) cobra.CheckErr(err) diff --git a/internal/cmd/object-storage/object_storage.go b/internal/cmd/object-storage/object_storage.go index a612598d3..0ba397592 100644 --- a/internal/cmd/object-storage/object_storage.go +++ b/internal/cmd/object-storage/object_storage.go @@ -16,8 +16,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "object-storage", - Short: "Provides functionality regarding Object Storage", - Long: "Provides functionality regarding Object Storage.", + Short: "Provides functionality for Object Storage", + Long: "Provides functionality for Object Storage.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/organization/member/member.go b/internal/cmd/organization/member/member.go index fecdcfc1a..cf7c515d8 100644 --- a/internal/cmd/organization/member/member.go +++ b/internal/cmd/organization/member/member.go @@ -14,8 +14,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "member", - Short: "Provides functionality regarding organization members", - Long: "Provides functionality regarding organization members.", + Short: "Manages organization members", + Long: "Manages organization members.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/organization/organization.go b/internal/cmd/organization/organization.go index fb2b6ca57..3d34090fd 100644 --- a/internal/cmd/organization/organization.go +++ b/internal/cmd/organization/organization.go @@ -15,9 +15,9 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "organization", - Short: "Provides functionality regarding organizations", + Short: "Manages organizations", Long: fmt.Sprintf("%s\n%s", - "Provides functionality regarding organizations.", + "Manages organizations.", "An active STACKIT organization is the root element of the resource hierarchy and a prerequisite to use any STACKIT Cloud Resource / Service.", ), Args: args.NoArgs, diff --git a/internal/cmd/organization/role/role.go b/internal/cmd/organization/role/role.go index 41f87752a..f32189bf5 100644 --- a/internal/cmd/organization/role/role.go +++ b/internal/cmd/organization/role/role.go @@ -12,8 +12,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "role", - Short: "Provides functionality regarding organization roles", - Long: "Provides functionality regarding organization roles.", + Short: "Manages organization roles", + Long: "Manages organization roles.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/project/member/member.go b/internal/cmd/project/member/member.go index 38340c1f2..658f6ff7c 100644 --- a/internal/cmd/project/member/member.go +++ b/internal/cmd/project/member/member.go @@ -14,8 +14,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "member", - Short: "Provides functionality regarding project members", - Long: "Provides functionality regarding project members.", + Short: "Manages project members", + Long: "Manages project members.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/project/project.go b/internal/cmd/project/project.go index b4cf79228..ded8f8444 100644 --- a/internal/cmd/project/project.go +++ b/internal/cmd/project/project.go @@ -20,9 +20,9 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "project", - Short: "Provides functionality regarding projects", + Short: "Manages projects", Long: fmt.Sprintf("%s\n%s", - "Provides functionality regarding projects.", + "Provides functionality for projects.", "A project is a container for resources which is the service that you can purchase from STACKIT.", ), Args: args.NoArgs, diff --git a/internal/cmd/project/role/role.go b/internal/cmd/project/role/role.go index c32d3d224..b460e54b7 100644 --- a/internal/cmd/project/role/role.go +++ b/internal/cmd/project/role/role.go @@ -12,8 +12,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "role", - Short: "Provides functionality regarding project roles", - Long: "Provides functionality regarding project roles.", + Short: "Manages project roles", + Long: "Manages project roles.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/root.go b/internal/cmd/root.go index 8f4193142..c09feab57 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -32,6 +32,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/fatih/color" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -100,9 +101,27 @@ func NewRootCmd(version, date string, p *print.Printer) *cobra.Command { c.Flags().BoolP("help", "h", false, fmt.Sprintf("Help for %q", c.CommandPath())) }) + beautifyUsageTemplate(cmd) + return cmd } +func beautifyUsageTemplate(cmd *cobra.Command) { + cobra.AddTemplateFunc("WhiteBold", color.New(color.FgHiWhite, color.Bold).SprintFunc()) + usageTemplate := cmd.UsageTemplate() + usageTemplate = strings.NewReplacer( + `Usage:`, `{{WhiteBold "USAGE"}}`, + `Examples:`, `{{WhiteBold "EXAMPLES"}}`, + `Aliases:`, `{{WhiteBold "ALIASES"}}`, + `Available Commands:`, `{{WhiteBold "AVAILABLE COMMANDS"}}`, + `Additional Commands:`, `{{WhiteBold "ADDITIONAL COMMANDS"}}`, + `Global Flags:`, `{{WhiteBold "GLOBAL FLAGS"}}`, + `Flags:`, `{{WhiteBold "FLAGS"}}`, + `Additional help topics:`, `{{WhiteBold "ADDITIONAL HELP TOPICS"}}`, + ).Replace(usageTemplate) + cmd.SetUsageTemplate(usageTemplate) +} + func configureFlags(cmd *cobra.Command) error { cmd.Flags().BoolP("version", "v", false, `Show "stackit" version`) diff --git a/internal/cmd/root_test.go b/internal/cmd/root_test.go new file mode 100644 index 000000000..71861a46f --- /dev/null +++ b/internal/cmd/root_test.go @@ -0,0 +1,75 @@ +package cmd + +import ( + "errors" + "testing" + + "github.com/spf13/cobra" + pkgErrors "github.com/stackitcloud/stackit-cli/internal/pkg/errors" +) + +var cmd *cobra.Command +var service *cobra.Command +var resource *cobra.Command +var operation *cobra.Command + +func setupCmd() { + cmd = &cobra.Command{ + Use: "stackit", + } + service = &cobra.Command{ + Use: "service", + } + resource = &cobra.Command{ + Use: "resource", + } + operation = &cobra.Command{ + Use: "operation", + } + cmd.AddCommand(service) + service.AddCommand(resource) + resource.AddCommand(operation) +} + +func TestBeautifyUnknownAndMissingCommandsError(t *testing.T) { + tests := []struct { + description string + inputError error + command *cobra.Command + expectedMsg string + isNotUnknownFlagError bool + }{ + { + description: "root command, extra input is a flag", + inputError: errors.New("unknown flag: --something"), + command: cmd, + expectedMsg: pkgErrors.SUBCOMMAND_MISSING, + }, + { + description: "non unknown flag error, return the same", + inputError: errors.New("some error"), + command: cmd, + expectedMsg: "some error", + isNotUnknownFlagError: true, + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + actualError := beautifyUnknownAndMissingCommandsError(cmd, tt.inputError) + + if tt.isNotUnknownFlagError { + if actualError.Error() != tt.expectedMsg { + t.Fatalf("expected error message to be %s, got %s", tt.expectedMsg, actualError.Error()) + } + return + } + + appendedErr := pkgErrors.AppendUsageTip(errors.New(tt.expectedMsg), cmd) + if actualError.Error() != appendedErr.Error() { + t.Fatalf("expected error to be %s, got %s", appendedErr.Error(), actualError.Error()) + } + }) + } +} diff --git a/internal/cmd/service-account/key/key.go b/internal/cmd/service-account/key/key.go index 96ec51ae3..969e3df91 100644 --- a/internal/cmd/service-account/key/key.go +++ b/internal/cmd/service-account/key/key.go @@ -16,8 +16,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "key", - Short: "Provides functionality regarding service account keys", - Long: "Provides functionality regarding service account keys.", + Short: "Provides functionality for service account keys", + Long: "Provides functionality for service account keys.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/service-account/token/token.go b/internal/cmd/service-account/token/token.go index af6d363d4..45570ea97 100644 --- a/internal/cmd/service-account/token/token.go +++ b/internal/cmd/service-account/token/token.go @@ -14,8 +14,8 @@ import ( func NewCmd(p *print.Printer) *cobra.Command { cmd := &cobra.Command{ Use: "token", - Short: "Provides functionality regarding service account tokens", - Long: "Provides functionality regarding service account tokens.", + Short: "Provides functionality for service account tokens", + Long: "Provides functionality for service account tokens.", Args: args.NoArgs, Run: utils.CmdHelp, } diff --git a/internal/cmd/ske/cluster/generate-payload/generate_payload.go b/internal/cmd/ske/cluster/generate-payload/generate_payload.go index 130495b0a..054fea2b3 100644 --- a/internal/cmd/ske/cluster/generate-payload/generate_payload.go +++ b/internal/cmd/ske/cluster/generate-payload/generate_payload.go @@ -8,6 +8,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/args" "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" + "github.com/stackitcloud/stackit-cli/internal/pkg/fileutils" "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" @@ -20,11 +21,13 @@ import ( const ( clusterNameFlag = "cluster-name" + filePathFlag = "file-path" ) type inputModel struct { *globalflags.GlobalFlagModel ClusterName *string + FilePath *string } func NewCmd(p *print.Printer) *cobra.Command { @@ -39,14 +42,17 @@ func NewCmd(p *print.Printer) *cobra.Command { Example: examples.Build( examples.NewExample( `Generate a payload with default values, and adapt it with custom values for the different configuration options`, - `$ stackit ske cluster generate-payload > ./payload.json`, + `$ stackit ske cluster generate-payload --file-path ./payload.json`, ``, `$ stackit ske cluster create my-cluster --payload @./payload.json`), examples.NewExample( `Generate a payload with values of a cluster, and adapt it with custom values for the different configuration options`, - `$ stackit ske cluster generate-payload --cluster-name my-cluster > ./payload.json`, + `$ stackit ske cluster generate-payload --cluster-name my-cluster --file-path ./payload.json`, ``, `$ stackit ske cluster update my-cluster --payload @./payload.json`), + examples.NewExample( + `Generate a payload with values of a cluster, and preview it in the terminal`, + `$ stackit ske cluster generate-payload --cluster-name my-cluster`), ), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.Background() @@ -83,7 +89,7 @@ func NewCmd(p *print.Printer) *cobra.Command { } } - return outputResult(p, payload) + return outputResult(p, model.FilePath, payload) }, } configureFlags(cmd) @@ -92,6 +98,7 @@ func NewCmd(p *print.Printer) *cobra.Command { func configureFlags(cmd *cobra.Command) { cmd.Flags().StringP(clusterNameFlag, "n", "", "If set, generates the payload with the current state of the given cluster. If unset, generates the payload with default values") + cmd.Flags().StringP(filePathFlag, "f", "", "If set, writes the payload to the given file. If unset, writes the payload to the standard output") } func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { @@ -106,6 +113,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { model := inputModel{ GlobalFlagModel: globalFlags, ClusterName: clusterName, + FilePath: flags.FlagToStringPointer(p, cmd, filePathFlag), } if p.IsVerbosityDebug() { @@ -125,12 +133,20 @@ func buildRequest(ctx context.Context, model *inputModel, apiClient *ske.APIClie return req } -func outputResult(p *print.Printer, payload *ske.CreateOrUpdateClusterPayload) error { +func outputResult(p *print.Printer, filePath *string, payload *ske.CreateOrUpdateClusterPayload) error { payloadBytes, err := json.MarshalIndent(*payload, "", " ") if err != nil { return fmt.Errorf("marshal payload: %w", err) } - p.Outputln(string(payloadBytes)) + + if filePath != nil { + err = fileutils.WriteToFile(*filePath, string(payloadBytes)) + if err != nil { + return fmt.Errorf("write payload to the file: %w", err) + } + } else { + p.Outputln(string(payloadBytes)) + } return nil } diff --git a/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go b/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go index 502596390..3cf60e949 100644 --- a/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go +++ b/internal/cmd/ske/cluster/generate-payload/generate_payload_test.go @@ -22,10 +22,16 @@ var testCtx = context.WithValue(context.Background(), testCtxKey{}, "foo") var testClient = &ske.APIClient{} var testProjectId = uuid.NewString() +const ( + testClusterName = "example-name" + testFilePath = "example-file" +) + func fixtureFlagValues(mods ...func(flagValues map[string]string)) map[string]string { flagValues := map[string]string{ projectIdFlag: testProjectId, - clusterNameFlag: "example-name", + clusterNameFlag: testClusterName, + filePathFlag: testFilePath, } for _, mod := range mods { mod(flagValues) @@ -39,7 +45,8 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { ProjectId: testProjectId, Verbosity: globalflags.VerbosityDefault, }, - ClusterName: utils.Ptr("example-name"), + ClusterName: utils.Ptr(testClusterName), + FilePath: utils.Ptr(testFilePath), } for _, mod := range mods { mod(model) @@ -48,7 +55,7 @@ func fixtureInputModel(mods ...func(model *inputModel)) *inputModel { } func fixtureRequest(mods ...func(request *ske.ApiGetClusterRequest)) ske.ApiGetClusterRequest { - request := testClient.GetCluster(testCtx, testProjectId, "example-name") + request := testClient.GetCluster(testCtx, testProjectId, testClusterName) for _, mod := range mods { mod(&request) } @@ -86,6 +93,16 @@ func TestParseInput(t *testing.T) { model.ClusterName = nil }), }, + { + description: "file path missing", + flagValues: fixtureFlagValues(func(flagValues map[string]string) { + delete(flagValues, filePathFlag) + }), + isValid: true, + expectedModel: fixtureInputModel(func(model *inputModel) { + model.FilePath = nil + }), + }, { description: "project id missing", flagValues: fixtureFlagValues(func(flagValues map[string]string) { diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go new file mode 100644 index 000000000..b3483a635 --- /dev/null +++ b/internal/pkg/config/config_test.go @@ -0,0 +1,71 @@ +package config + +import ( + "os" + "path/filepath" + "testing" + + "github.com/spf13/viper" +) + +func TestWrite(t *testing.T) { + tests := []struct { + description string + folderName string + folderExists bool + }{ + { + description: "write config file", + folderName: "", + }, + { + description: "write config file to new folder", + folderName: "new-folder", + }, + { + description: "write config file to existing folder", + folderName: "existing-folder", + folderExists: true, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + configPath := filepath.Join(os.TempDir(), tt.folderName, "config.json") + viper.SetConfigFile(configPath) + configFolderPath = filepath.Dir(configPath) + + if tt.folderExists { + err := os.MkdirAll(configFolderPath, os.ModePerm) + if err != nil { + t.Fatalf("expected error to be nil, got %v", err) + } + } + + err := Write() + if err != nil { + t.Fatalf("expected error to be nil, got %v", err) + } + + // Check if the file was created + _, err = os.Stat(configPath) + if os.IsNotExist(err) { + t.Fatalf("expected file to exist, got %v", err) + } + + // Delete the file + err = os.Remove(configPath) + if err != nil { + t.Fatalf("expected error to be nil, got %v", err) + } + + // Delete the folder + if tt.folderName != "" { + err = os.Remove(configFolderPath) + if err != nil { + t.Fatalf("expected error to be nil, got %v", err) + } + } + }) + } +} diff --git a/internal/pkg/config/file_utils.go b/internal/pkg/config/file_utils.go deleted file mode 100644 index 0895a9dc5..000000000 --- a/internal/pkg/config/file_utils.go +++ /dev/null @@ -1,26 +0,0 @@ -package config - -import ( - "fmt" - "os" -) - -// readFileIfExists reads the contents of a file and returns it as a string, along with a boolean indicating if the file exists. -// If the file does not exist, it returns an empty string and no error. -// If the file exists but cannot be read, it returns an error. -func readFileIfExists(filePath string) (contents string, exists bool, err error) { - _, err = os.Stat(filePath) - if err != nil { - if os.IsNotExist(err) { - return "", false, nil - } - return "", true, err - } - - content, err := os.ReadFile(filePath) - if err != nil { - return "", true, fmt.Errorf("read file: %w", err) - } - - return string(content), true, nil -} diff --git a/internal/pkg/config/profiles.go b/internal/pkg/config/profiles.go index ff07fbd7b..d2bae8013 100644 --- a/internal/pkg/config/profiles.go +++ b/internal/pkg/config/profiles.go @@ -7,6 +7,7 @@ import ( "regexp" "github.com/stackitcloud/stackit-cli/internal/pkg/errors" + "github.com/stackitcloud/stackit-cli/internal/pkg/fileutils" "github.com/stackitcloud/stackit-cli/internal/pkg/print" ) @@ -21,7 +22,7 @@ import ( func GetProfile() (string, error) { profile, profileSet := os.LookupEnv("STACKIT_CLI_PROFILE") if !profileSet { - contents, exists, err := readFileIfExists(profileFilePath) + contents, exists, err := fileutils.ReadFileIfExists(profileFilePath) if err != nil { return "", fmt.Errorf("read profile from file: %w", err) } diff --git a/internal/pkg/errors/errors_test.go b/internal/pkg/errors/errors_test.go new file mode 100644 index 000000000..8e7999d23 --- /dev/null +++ b/internal/pkg/errors/errors_test.go @@ -0,0 +1,629 @@ +package errors + +import ( + "errors" + "fmt" + "testing" + + "github.com/spf13/cobra" +) + +var cmd *cobra.Command +var service *cobra.Command +var resource *cobra.Command +var operation *cobra.Command + +func setupCmd() { + cmd = &cobra.Command{ + Use: "stackit", + } + service = &cobra.Command{ + Use: "service", + } + resource = &cobra.Command{ + Use: "resource", + } + operation = &cobra.Command{ + Use: "operation", + } + cmd.AddCommand(service) + service.AddCommand(resource) + resource.AddCommand(operation) +} + +func TestSimpleErrors(t *testing.T) { + tests := []struct { + description string + err error + expectedMsg string + }{ + { + description: "Test ProjectIdError", + err: &ProjectIdError{}, + expectedMsg: MISSING_PROJECT_ID, + }, + { + description: "Test EmptyUpdateError", + err: &EmptyUpdateError{}, + expectedMsg: EMPTY_UPDATE, + }, + { + description: "Test AuthError", + err: &AuthError{}, + expectedMsg: FAILED_AUTH, + }, + { + description: "Test ActivateServiceAccountError", + err: &ActivateServiceAccountError{}, + expectedMsg: FAILED_SERVICE_ACCOUNT_ACTIVATION, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + if tt.err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, tt.err.Error()) + } + }) + } +} + +func TestArgusInputPlanError(t *testing.T) { + tests := []struct { + description string + args []string + expectedMsg string + }{ + { + description: "base", + args: []string{"arg1", "arg2"}, + expectedMsg: fmt.Sprintf(ARGUS_INVALID_INPUT_PLAN, "stackit service resource operation arg1 arg2", "service"), + }, + { + description: "no args", + args: []string{}, + expectedMsg: fmt.Sprintf(ARGUS_INVALID_INPUT_PLAN, "stackit service resource operation", "service"), + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &ArgusInputPlanError{ + Cmd: operation, + Args: tt.args, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestArgusInvalidPlanError(t *testing.T) { + tests := []struct { + description string + details string + service string + expectedMsg string + }{ + { + description: "base", + details: "details", + service: "service", + expectedMsg: fmt.Sprintf(ARGUS_INVALID_PLAN, "details", "service"), + }, + { + description: "no details", + details: "", + service: "service", + expectedMsg: fmt.Sprintf(ARGUS_INVALID_PLAN, "", "service"), + }, + { + description: "no service", + details: "details", + service: "", + expectedMsg: fmt.Sprintf(ARGUS_INVALID_PLAN, "details", ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &ArgusInvalidPlanError{ + Service: tt.service, + Details: tt.details, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestDSAInputPlanError(t *testing.T) { + tests := []struct { + description string + args []string + expectedMsg string + }{ + { + description: "base", + args: []string{"arg1", "arg2"}, + expectedMsg: fmt.Sprintf(DSA_INVALID_INPUT_PLAN, "stackit service resource operation arg1 arg2", "service"), + }, + { + description: "no args", + args: []string{}, + expectedMsg: fmt.Sprintf(DSA_INVALID_INPUT_PLAN, "stackit service resource operation", "service"), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + setupCmd() + err := &DSAInputPlanError{ + Cmd: operation, + Args: tt.args, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestDSAInvalidPlanError(t *testing.T) { + tests := []struct { + description string + details string + service string + expectedMsg string + }{ + { + description: "base", + details: "details", + service: "service", + expectedMsg: fmt.Sprintf(DSA_INVALID_PLAN, "details", "service"), + }, + { + description: "no details", + details: "", + service: "service", + expectedMsg: fmt.Sprintf(DSA_INVALID_PLAN, "", "service"), + }, + { + description: "no service", + details: "details", + service: "", + expectedMsg: fmt.Sprintf(DSA_INVALID_PLAN, "details", ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &DSAInvalidPlanError{ + Service: tt.service, + Details: tt.details, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestDatabaseInputFlavorError(t *testing.T) { + tests := []struct { + description string + args []string + operation string + expectedMsg string + }{ + { + description: "base", + args: []string{"arg1", "arg2"}, + operation: "operation", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_INPUT_FLAVOR, "stackit service resource operation arg1 arg2", "service"), + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &DatabaseInputFlavorError{ + Cmd: operation, + Args: tt.args, + Operation: tt.operation, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestDatabaseInvalidFlavorError(t *testing.T) { + tests := []struct { + description string + details string + service string + expectedMsg string + }{ + { + description: "base", + details: "details", + service: "service", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_FLAVOR, "details", "service"), + }, + { + description: "no details", + details: "", + service: "service", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_FLAVOR, "", "service"), + }, + { + description: "no service", + details: "details", + service: "", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_FLAVOR, "details", ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &DatabaseInvalidFlavorError{ + Service: tt.service, + Details: tt.details, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestDatabaseInvalidStorageError(t *testing.T) { + tests := []struct { + description string + details string + service string + flavorId string + expectedMsg string + }{ + { + description: "base", + details: "details", + service: "service", + flavorId: "flavorId", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_STORAGE, "details", "service", "flavorId"), + }, + { + description: "no details", + details: "", + service: "service", + flavorId: "flavorId", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_STORAGE, "", "service", "flavorId"), + }, + { + description: "no service", + details: "details", + service: "", + flavorId: "flavorId", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_STORAGE, "details", "", "flavorId"), + }, + { + description: "no flavorId", + details: "details", + service: "service", + flavorId: "", + expectedMsg: fmt.Sprintf(DATABASE_INVALID_STORAGE, "details", "service", ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &DatabaseInvalidStorageError{ + Service: tt.service, + Details: tt.details, + FlavorId: tt.flavorId, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestFlagValidationError(t *testing.T) { + tests := []struct { + description string + flag string + details string + expectedMsg string + }{ + { + description: "base", + flag: "flag", + details: "details", + expectedMsg: fmt.Sprintf(FLAG_VALIDATION, "flag", "details"), + }, + { + description: "no flag", + flag: "", + details: "details", + expectedMsg: fmt.Sprintf(FLAG_VALIDATION, "", "details"), + }, + { + description: "no details", + flag: "flag", + details: "", + expectedMsg: fmt.Sprintf(FLAG_VALIDATION, "flag", ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &FlagValidationError{ + Flag: tt.flag, + Details: tt.details, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestRequiredMutuallyExclusiveFlagsError(t *testing.T) { + tests := []struct { + description string + flags []string + expectedMsg string + }{ + { + description: "base", + flags: []string{"flag1", "flag2"}, + expectedMsg: fmt.Sprintf(REQUIRED_MUTUALLY_EXCLUSIVE_FLAGS, "flag1, flag2"), + }, + { + description: "no flags", + flags: []string{}, + expectedMsg: fmt.Sprintf(REQUIRED_MUTUALLY_EXCLUSIVE_FLAGS, ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &RequiredMutuallyExclusiveFlagsError{ + Flags: tt.flags, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestArgValidationError(t *testing.T) { + tests := []struct { + description string + arg string + details string + expectedMsg string + }{ + { + description: "base", + arg: "arg", + details: "details", + expectedMsg: fmt.Sprintf(ARG_VALIDATION, "arg", "details"), + }, + { + description: "no arg", + arg: "", + details: "details", + expectedMsg: fmt.Sprintf(ARG_VALIDATION, "", "details"), + }, + { + description: "no details", + arg: "arg", + details: "", + expectedMsg: fmt.Sprintf(ARG_VALIDATION, "arg", ""), + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &ArgValidationError{ + Arg: tt.arg, + Details: tt.details, + } + + if err.Error() != tt.expectedMsg { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestSingleArgExpectedError(t *testing.T) { + tests := []struct { + description string + expected string + count int + expectedMsg string + }{ + { + description: "base", + expected: "expected", + count: 1, + expectedMsg: fmt.Sprintf(ARG_MISSING, "expected"), + }, + { + description: "multiple", + expected: "expected", + count: 2, + expectedMsg: fmt.Sprintf(SINGLE_ARG_EXPECTED, "expected", 2), + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &SingleArgExpectedError{ + Expected: tt.expected, + Count: tt.count, + Cmd: operation, + } + + appendedErr := AppendUsageTip(errors.New(tt.expectedMsg), operation) + + if err.Error() != appendedErr.Error() { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestSingleOptionalArgExpectedError(t *testing.T) { + tests := []struct { + description string + expected string + count int + expectedMsg string + }{ + { + description: "base", + expected: "expected", + count: 1, + expectedMsg: fmt.Sprintf(SINGLE_OPTIONAL_ARG_EXPECTED, "expected", 1), + }, + { + description: "multiple", + expected: "expected", + count: 2, + expectedMsg: fmt.Sprintf(SINGLE_OPTIONAL_ARG_EXPECTED, "expected", 2), + }, + { + description: "no count", + expected: "expected", + count: 0, + expectedMsg: fmt.Sprintf(SINGLE_OPTIONAL_ARG_EXPECTED, "expected", 0), + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &SingleOptionalArgExpectedError{ + Expected: tt.expected, + Count: tt.count, + Cmd: operation, + } + + appendedErr := AppendUsageTip(errors.New(tt.expectedMsg), operation) + + if err.Error() != appendedErr.Error() { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestInputUnknownError(t *testing.T) { + tests := []struct { + description string + input string + command *cobra.Command + expectedMsg string + }{ + { + description: "extra argument, not a subcommand", + input: "extra", + command: operation, + expectedMsg: fmt.Sprintf(ARG_UNKNOWN, "extra"), + }, + { + description: "extra subcommand", + input: "extra", + command: service, + expectedMsg: fmt.Sprintf(SUBCOMMAND_UNKNOWN, "extra"), + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &InputUnknownError{ + ProvidedInput: tt.input, + Cmd: tt.command, + } + + appendedErr := AppendUsageTip(errors.New(tt.expectedMsg), tt.command) + + if err.Error() != appendedErr.Error() { + t.Fatalf("expected error to be %s, got %s", appendedErr.Error(), err.Error()) + } + }) + } +} + +func TestSubcommandMissingError(t *testing.T) { + tests := []struct { + description string + expectedMsg string + }{ + { + description: "base", + expectedMsg: SUBCOMMAND_MISSING, + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := &SubcommandMissingError{ + Cmd: cmd, + } + + appendedErr := AppendUsageTip(errors.New(tt.expectedMsg), cmd) + + if err.Error() != appendedErr.Error() { + t.Fatalf("expected error to be %s, got %s", tt.expectedMsg, err.Error()) + } + }) + } +} + +func TestAppendUsageTip(t *testing.T) { + tests := []struct { + description string + err error + expectedError error + }{ + { + description: "base", + err: fmt.Errorf("error"), + expectedError: fmt.Errorf("%w.\n\n%s", fmt.Errorf("error"), fmt.Sprintf(USAGE_TIP, "stackit")), + }, + } + + setupCmd() + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := AppendUsageTip(tt.err, cmd) + + if err.Error() != tt.expectedError.Error() { + t.Fatalf("expected error to be %s, got %s", tt.expectedError, err.Error()) + } + }) + } +} diff --git a/internal/pkg/fileutils/file_utils.go b/internal/pkg/fileutils/file_utils.go new file mode 100644 index 000000000..1d1cf767e --- /dev/null +++ b/internal/pkg/fileutils/file_utils.go @@ -0,0 +1,48 @@ +package fileutils + +import ( + "fmt" + "os" +) + +func WriteToFile(outputFileName, content string) (err error) { + fo, err := os.Create(outputFileName) + if err != nil { + return fmt.Errorf("create output file: %w", err) + } + defer func() { + tempErr := fo.Close() + if tempErr != nil { + if err != nil { + err = fmt.Errorf("%w; close output file: %w", err, tempErr) + } else { + err = fmt.Errorf("close output file: %w", tempErr) + } + } + }() + _, err = fo.WriteString(content) + if err != nil { + return fmt.Errorf("write content to output file: %w", err) + } + return err +} + +// ReadFileIfExists reads the contents of a file and returns it as a string, along with a boolean indicating if the file exists. +// If the file does not exist, it returns an empty string and no error. +// If the file exists but cannot be read, it returns an error. +func ReadFileIfExists(filePath string) (contents string, exists bool, err error) { + _, err = os.Stat(filePath) + if err != nil { + if os.IsNotExist(err) { + return "", false, nil + } + return "", true, err + } + + content, err := os.ReadFile(filePath) + if err != nil { + return "", true, fmt.Errorf("read file: %w", err) + } + + return string(content), true, nil +} diff --git a/internal/pkg/config/file_utils_test.go b/internal/pkg/fileutils/file_utils_test.go similarity index 50% rename from internal/pkg/config/file_utils_test.go rename to internal/pkg/fileutils/file_utils_test.go index d7f299cb6..96bf20b12 100644 --- a/internal/pkg/config/file_utils_test.go +++ b/internal/pkg/fileutils/file_utils_test.go @@ -1,9 +1,47 @@ -package config +package fileutils import ( + "os" "testing" ) +const outputFilePath = "./testPayload.json" + +func TestWriteToFile(t *testing.T) { + tests := []struct { + description string + content string + outputFile string + }{ + { + description: "write into file", + content: "Test message", + outputFile: outputFilePath, + }, + } + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + err := WriteToFile(tt.outputFile, tt.content) + if err != nil { + t.Fatalf("unexpected error: %s", err.Error()) + } + + output, err := os.ReadFile(tt.outputFile) + if err != nil { + t.Fatalf("unexpected error: %s", err.Error()) + } + if string(output) != tt.content { + t.Errorf("unexpected output: got %q, want %q", output, tt.content) + } + }) + } + // Cleanup + err := os.RemoveAll(outputFilePath) + if err != nil { + t.Errorf("failed cleaning test data") + } +} + func TestReadFileIfExists(t *testing.T) { tests := []struct { description string @@ -32,7 +70,7 @@ func TestReadFileIfExists(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - content, exists, err := readFileIfExists(tt.filePath) + content, exists, err := ReadFileIfExists(tt.filePath) if err != nil { t.Errorf("read file: %v", err) } diff --git a/internal/pkg/config/test-data/empty-file.txt b/internal/pkg/fileutils/test-data/empty-file.txt similarity index 100% rename from internal/pkg/config/test-data/empty-file.txt rename to internal/pkg/fileutils/test-data/empty-file.txt diff --git a/internal/pkg/config/test-data/file-with-content.txt b/internal/pkg/fileutils/test-data/file-with-content.txt similarity index 100% rename from internal/pkg/config/test-data/file-with-content.txt rename to internal/pkg/fileutils/test-data/file-with-content.txt diff --git a/internal/pkg/config/test-data/folder-exists/dummy.txt b/internal/pkg/fileutils/test-data/folder-exists/dummy.txt similarity index 100% rename from internal/pkg/config/test-data/folder-exists/dummy.txt rename to internal/pkg/fileutils/test-data/folder-exists/dummy.txt diff --git a/internal/pkg/projectname/project_name_test.go b/internal/pkg/projectname/project_name_test.go new file mode 100644 index 000000000..25239c8f4 --- /dev/null +++ b/internal/pkg/projectname/project_name_test.go @@ -0,0 +1,61 @@ +package projectname + +import ( + "context" + "testing" + + "github.com/google/uuid" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/stackitcloud/stackit-cli/internal/pkg/config" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" +) + +var testProjectId = uuid.NewString() + +func TestGetProjectName(t *testing.T) { + tests := []struct { + description string + projectName string + projectId string + isValid bool + }{ + { + description: "Project name from config", + projectName: "project-name", + projectId: testProjectId, + isValid: true, + }, + { + description: "empty project name and id", + projectName: "", + projectId: "", + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + viper.Set(config.ProjectNameKey, tt.projectName) + viper.Set(config.ProjectIdKey, tt.projectId) + defer viper.Reset() + p := print.NewPrinter() + cmd := &cobra.Command{} + + projectName, err := GetProjectName(context.Background(), p, cmd) + if err != nil { + if tt.isValid { + t.Fatalf("unexpected error: %v", err) + } + return + } + if !tt.isValid { + t.Fatalf("expected error, got project name %q", projectName) + } + + if projectName != tt.projectName { + t.Fatalf("expected project name %q, got %q", tt.projectName, projectName) + } + }) + } +} diff --git a/internal/pkg/services/mongodbflex/utils/utils_test.go b/internal/pkg/services/mongodbflex/utils/utils_test.go index bdea1a34b..1024c5710 100644 --- a/internal/pkg/services/mongodbflex/utils/utils_test.go +++ b/internal/pkg/services/mongodbflex/utils/utils_test.go @@ -644,3 +644,55 @@ func TestGetRestoreStatus(t *testing.T) { }) } } + +func TestGetInstanceType(t *testing.T) { + tests := []struct { + description string + numReplicas int64 + expectedOutput string + isValid bool + }{ + { + description: "single", + numReplicas: 1, + expectedOutput: "Single", + isValid: true, + }, + { + description: "replica set", + numReplicas: 3, + expectedOutput: "Replica", + isValid: true, + }, + { + description: "sharded cluster", + numReplicas: 9, + expectedOutput: "Sharded", + isValid: true, + }, + { + description: "invalid", + numReplicas: 0, + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + output, err := GetInstanceType(tt.numReplicas) + if !tt.isValid { + if err == nil { + t.Fatalf("did not fail on invalid input") + } + return + } + if err != nil { + t.Fatalf("failed on valid input: %v", err) + } + + if output != tt.expectedOutput { + t.Fatalf("expected output to be %s, got %s", tt.expectedOutput, output) + } + }) + } +} diff --git a/internal/pkg/services/postgresflex/utils/utils_test.go b/internal/pkg/services/postgresflex/utils/utils_test.go index c25d4a1d3..250295e79 100644 --- a/internal/pkg/services/postgresflex/utils/utils_test.go +++ b/internal/pkg/services/postgresflex/utils/utils_test.go @@ -569,3 +569,49 @@ func TestGetUserName(t *testing.T) { }) } } + +func TestGetInstanceType(t *testing.T) { + tests := []struct { + description string + numReplicas int64 + expectedOutput string + isValid bool + }{ + { + description: "single", + numReplicas: 1, + expectedOutput: "Single", + isValid: true, + }, + { + description: "replica set", + numReplicas: 3, + expectedOutput: "Replica", + isValid: true, + }, + { + description: "invalid", + numReplicas: 0, + isValid: false, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + output, err := GetInstanceType(tt.numReplicas) + if !tt.isValid { + if err == nil { + t.Fatalf("did not fail on invalid input") + } + return + } + if err != nil { + t.Fatalf("failed on valid input: %v", err) + } + + if output != tt.expectedOutput { + t.Fatalf("expected output to be %s, got %s", tt.expectedOutput, output) + } + }) + } +} diff --git a/internal/pkg/services/ske/utils/utils_test.go b/internal/pkg/services/ske/utils/utils_test.go index fe977e1f2..2158e175a 100644 --- a/internal/pkg/services/ske/utils/utils_test.go +++ b/internal/pkg/services/ske/utils/utils_test.go @@ -610,3 +610,30 @@ func TestWriteConfigFile(t *testing.T) { t.Errorf("failed cleaning test data") } } + +func TestGetDefaultKubeconfigPath(t *testing.T) { + tests := []struct { + description string + }{ + { + description: "base", + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + output, err := GetDefaultKubeconfigPath() + + if err != nil { + t.Errorf("failed on valid input") + } + userHome, err := os.UserHomeDir() + if err != nil { + t.Errorf("could not get user home directory") + } + if output != filepath.Join(userHome, ".kube", "config") { + t.Errorf("expected output to be %s, got %s", filepath.Join(userHome, ".kube", "config"), output) + } + }) + } +}