From 282b98f33538189a2d3dafec2798c29bc7522f31 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Wed, 24 Jun 2020 14:51:07 -0400 Subject: [PATCH] cli v0.5.2 add user update commands fixes #117 --- .github/workflows/pre_release.yml | 2 +- client/tc/HISTORY.rst | 5 ++ client/tc/azext_tc/_help.py | 136 +++++++++++++++++------------- client/tc/azext_tc/_params.py | 15 +++- client/tc/azext_tc/commands.py | 15 ++++ client/tc/azext_tc/custom.py | 90 ++++++++++++++++---- client/tc/setup.py | 2 +- linter_exclusions.yml | 10 +++ 8 files changed, 196 insertions(+), 79 deletions(-) create mode 100644 linter_exclusions.yml diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 0f48312f..5814c70b 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -5,7 +5,7 @@ on: branches: [master] env: - TC_CLI_VERSION: 0.5.1 + TC_CLI_VERSION: 0.5.2 BUILD_CONFIGURATION: Release SOURCE_DIRECTORY: ./src diff --git a/client/tc/HISTORY.rst b/client/tc/HISTORY.rst index 071b0401..632cb628 100644 --- a/client/tc/HISTORY.rst +++ b/client/tc/HISTORY.rst @@ -3,6 +3,11 @@ Release History =============== +0.5.2 +++++++ +* Preview release +* Add az tc [project] user update commands + 0.5.1 ++++++ * Preview release diff --git a/client/tc/azext_tc/_help.py b/client/tc/azext_tc/_help.py index ab9660d2..9736a756 100644 --- a/client/tc/azext_tc/_help.py +++ b/client/tc/azext_tc/_help.py @@ -30,9 +30,9 @@ type: command short-summary: Upgrade a TeamCloud instance version. examples: - name: Upgrade a TeamCloud instance to the latest release. - text: az tc upgrade --base-url https://myurl + text: az tc upgrade --base-url url - name: Upgrade a TeamCloud instance to a specific pre-release. - text: az tc upgrade --base-url https://myurl --version v0.1.1 + text: az tc upgrade --base-url url --version v0.1.1 """ helps['tc status'] = """ @@ -40,9 +40,9 @@ type: command short-summary: Get the status of a long-running operation. examples: - name: Get the status of a TeamCloud operation like creating a new provider. - text: az tc status --base-url https://myurl --tracking-id myTrackingIdGuid + text: az tc status --base-url url --tracking-id trackingId - name: Get the status of a Project operation like creating a new project user. - text: az tc status --base-url https://myurl --project myProjectId --tracking-id myTrackingIdGuid + text: az tc status --base-url url --project project --tracking-id trackingId """ # ---------------- @@ -59,7 +59,7 @@ type: command short-summary: Create a new TeamCloud user. examples: - name: Create a new TeamCloud user with Admin role. - text: az tc user create --base-url https://myurl --name 'user@microsoft.com' --role Admin --properties prop=value + text: az tc user create --base-url url --name user --role Admin --properties prop=value """ helps['tc user delete'] = """ @@ -67,9 +67,9 @@ type: command short-summary: Delete a TeamCloud user. examples: - name: Delete a user by email address. - text: az tc user delete --base-url https://myurl --name 'user@microsoft.com' + text: az tc user delete --base-url url --name user - name: Delete a user by id. - text: az tc user delete --base-url https://myurl --name userId + text: az tc user delete --base-url url --name userId """ helps['tc user list'] = """ @@ -77,9 +77,9 @@ type: command short-summary: List all TeamCloud users. examples: - name: List all users. - text: az tc user list --base-url https://myurl + text: az tc user list --base-url url - name: List all users in table format. - text: az tc user list --base-url https://myurl -o table + text: az tc user list --base-url url -o table """ helps['tc user show'] = """ @@ -87,9 +87,21 @@ type: command short-summary: Get a TeamCloud user. examples: - name: Get a user by email address. - text: az tc user show --base-url https://myurl --name 'user@microsoft.com' + text: az tc user show --base-url url --name user - name: Get a user by id. - text: az tc user show --base-url https://myurl --name userId + text: az tc user show --base-url url --name userId +""" + +helps['tc user update'] = """ +type: command +short-summary: Update a TeamCloud user. +examples: + - name: Update a user's role. + text: az tc user update --base-url url --name user --role Creator + - name: Add a property to a user. + text: az tc user update --base-url url --name user --properties prop=value + - name: Add a property to a user using generic set. + text: az tc user update --base-url url --name user --set properties.prop=value """ # ---------------- @@ -106,7 +118,7 @@ type: command short-summary: Create a new TeamCloud tag. examples: - name: Create a new TeamCloud tag. - text: az tc tag create --base-url https://myurl --key myTag --value myTagValue + text: az tc tag create --base-url url --key key --value value """ helps['tc tag delete'] = """ @@ -114,7 +126,7 @@ type: command short-summary: Delete a TeamCloud tag. examples: - name: Delete a TeamCloud tag by key. - text: az tc tag delete --base-url https://myurl --key myTag + text: az tc tag delete --base-url url --key key """ helps['tc tag list'] = """ @@ -122,7 +134,7 @@ type: command short-summary: List all TeamCloud tags. examples: - name: List all TeamCloud tags in table format. - text: az tc tag list --base-url https://myurl -o table + text: az tc tag list --base-url url -o table """ helps['tc tag show'] = """ @@ -130,7 +142,7 @@ type: command short-summary: Get a TeamCloud tag. examples: - name: Get a TeamCloud tag by key. - text: az tc tag show --base-url https://myurl --key myTag + text: az tc tag show --base-url url --key key """ # ---------------- @@ -147,19 +159,17 @@ type: command short-summary: Create a new project. examples: - name: Create a new project using the default project type. - text: az tc project create --base-url https://myurl --name MyProject1 --tags tag=value --properties prop=value + text: az tc project create --base-url url --name project --tags tag=value --properties prop=value - name: Create a new project using a specific project type. - text: az tc project create --base-url https://myurl --name MyProject2 --project-type my.project.type --tags tag=value --properties prop=value + text: az tc project create --base-url url --name project --project-type type --tags tag=value --properties prop=value """ helps['tc project delete'] = """ type: command short-summary: Delete a project. examples: - - name: Delete a project by name. - text: az tc project delete --base-url https://myurl --name MyProject1 - - name: Delete a project by id. - text: az tc project delete --base-url https://myurl --name myProjectId + - name: Delete a project by name or id. + text: az tc project delete --base-url url --name project """ helps['tc project list'] = """ @@ -167,19 +177,17 @@ type: command short-summary: List all projects. examples: - name: List all projects. - text: az tc project list --base-url https://myurl + text: az tc project list --base-url url - name: List all projects in table format. - text: az tc project list --base-url https://myurl -o table + text: az tc project list --base-url url -o table """ helps['tc project show'] = """ type: command short-summary: Get a project. examples: - - name: Get a project by name. - text: az tc project show --base-url https://myurl --name MyProject1 - - name: Get a project by id. - text: az tc project show --base-url https://myurl --name myProjectId + - name: Get a project by name or id. + text: az tc project show --base-url url --name project """ # ---------------- @@ -196,17 +204,15 @@ type: command short-summary: Create a new project user. examples: - name: Create a new project user with Owner role. - text: az tc project user create --base-url https://myurle --project myProjectId --name 'user@microsoft.com' --role Owner --properties prop=value + text: az tc project user create --base-url urle --project project --name user --role Owner --properties prop=value """ helps['tc project user delete'] = """ type: command short-summary: Delete a project user. examples: - - name: Delete a project user by email address. - text: az tc project user delete --base-url https://myurl --project myProjectId --name 'user@microsoft.com' - - name: Delete a project user by id. - text: az tc project user delete --base-url https://myurl --project myProjectId --name userId + - name: Delete a project user by email address or id. + text: az tc project user delete --base-url url --project project --name user """ helps['tc project user list'] = """ @@ -214,19 +220,29 @@ type: command short-summary: List all project users. examples: - name: List all project users. - text: az tc project user list --base-url https://myurl --project myProjectId + text: az tc project user list --base-url url --project project - name: List all project users in table format. - text: az tc project user list --base-url https://myurl --project myProjectId -o table + text: az tc project user list --base-url url --project project -o table """ helps['tc project user show'] = """ type: command short-summary: Get a project user. examples: - - name: Get a project user by email address. - text: az tc project user show --base-url https://myurl --project myProjectId --name 'user@microsoft.com' - - name: Get a project user by id. - text: az tc project user show --base-url https://myurl --project myProjectId --name userId + - name: Get a project user by email address or id. + text: az tc project user show --base-url url --project project --name user +""" + +helps['tc project user update'] = """ +type: command +short-summary: Update a project user. +examples: + - name: Update a user's role. + text: az tc project user update --base-url url --project project --name user --role Owner + - name: Add a property to a user. + text: az tc project user update --base-url url --project project --name user --properties prop=value + - name: Add a property to a user using generic set. + text: az tc project user update --base-url url --project project --name user --set properties.prop=value """ # ---------------- @@ -243,7 +259,7 @@ type: command short-summary: Create a new project tag. examples: - name: Create a new project tag. - text: az tc project tag create --base-url https://myurl --project myProjectId --key myTag --value myTagValue + text: az tc project tag create --base-url url --project project --key key --value value """ helps['tc project tag delete'] = """ @@ -251,7 +267,7 @@ type: command short-summary: Delete a project tag. examples: - name: Delete a project tag by key. - text: az tc project tag delete --base-url https://myurl --project myProjectId --key myTag + text: az tc project tag delete --base-url url --project project --key key """ helps['tc project tag list'] = """ @@ -259,7 +275,7 @@ type: command short-summary: List all project tags. examples: - name: List all project tags in table format. - text: az tc project tag list --base-url https://myurl --project myProjectId -o table + text: az tc project tag list --base-url url --project project -o table """ helps['tc project tag show'] = """ @@ -267,7 +283,7 @@ type: command short-summary: Get a project tag. examples: - name: Get a project tag by key. - text: az tc project tag show --base-url https://myurl --project myProjectId --key myTag + text: az tc project tag show --base-url url --project project --key key """ # ---------------- @@ -286,14 +302,14 @@ examples: - name: Create a new default project type. text: | az tc project-type create \\ - --base-url https://myurl \\ - --name my.project.type \\ + --base-url url \\ + --name type \\ --location eastus \\ - --subscriptions subsciptionId1 subsciptionId2 subsciptionId3 \\ + --subscriptions subscriptionId1 subscriptionId2 subscriptionId3 \\ --subscription-capacity 5 \\ --resource-group-name-prefix TC_ \\ - --provider my.provider.id.one prop1=val1 prop2=val2 \\ - --provider my.provider.id.two prop3=val3 prop4=val4 depends_on=my.provider.id.one \\ + --provider provider.one prop1=val1 prop2=val2 \\ + --provider provider.two prop3=val3 prop4=val4 depends_on=provider.one \\ --default """ @@ -302,7 +318,7 @@ type: command short-summary: Delete a project type. examples: - name: Delete a project type. - text: az tc project-type delete --base-url https://myurl --name my.project.type + text: az tc project-type delete --base-url url --name type """ helps['tc project-type list'] = """ @@ -310,9 +326,9 @@ type: command short-summary: List all project types. examples: - name: List all project types. - text: az tc project-type list --base-url https://myurl + text: az tc project-type list --base-url url - name: List all project types in table format. - text: az tc project-type list --base-url https://myurl -o table + text: az tc project-type list --base-url url -o table """ helps['tc project-type show'] = """ @@ -320,7 +336,7 @@ type: command short-summary: Get a project type. examples: - name: Get a project-type. - text: az tc project-type show --base-url https://myurl --name my.project.type + text: az tc project-type show --base-url url --name type """ # ---------------- @@ -339,7 +355,7 @@ examples: - name: Create a new provider. text: | az tc provider create \\ - --base-url https://myurl \\ + --base-url url \\ --name azure.devtestlabs \\ --url https://my-provider.azurewebsites.net \\ --auth-code cmFuZG9tcmFuZG9tcmFuZG9tcmFuZG9tcmFuZG9tcmFuZG9tcmFuZA== \\ @@ -351,7 +367,7 @@ type: command short-summary: Delete a provider. examples: - name: Delete a provider. - text: az tc provider delete --base-url https://myurl --name my.provider.id + text: az tc provider delete --base-url url --name provider """ helps['tc provider list'] = """ @@ -359,9 +375,9 @@ type: command short-summary: List all providers. examples: - name: List all providers. - text: az tc provider list --base-url https://myurl + text: az tc provider list --base-url url - name: List all providers in table format. - text: az tc provider list --base-url https://myurl -o table + text: az tc provider list --base-url url -o table """ helps['tc provider list-available'] = """ @@ -379,7 +395,7 @@ type: command short-summary: Get a provider. examples: - name: Get a provider. - text: az tc provider show --base-url https://myurl --name my.provider.id + text: az tc provider show --base-url url --name provider """ helps['tc provider deploy'] = """ @@ -387,9 +403,9 @@ type: command short-summary: Deploy a provider. examples: - name: Deploy a provider. - text: az tc provider deploy --base-url https://myurl --location eastus --name azure.devtestlabs + text: az tc provider deploy --base-url url --location eastus --name azure.devtestlabs - name: Deploy a provider to a specific pre-release. - text: az tc provider deploy --base-url https://myurl --location eastus --name azure.devtestlabs --version v0.1.1 + text: az tc provider deploy --base-url url --location eastus --name azure.devtestlabs --version v0.1.1 """ helps['tc provider upgrade'] = """ @@ -397,7 +413,7 @@ type: command short-summary: Upgrade a provider version. examples: - name: Upgrade provider to the latest version. - text: az tc provider upgrade --base-url https://myurl --name azure.devtestlabs + text: az tc provider upgrade --base-url url --name azure.devtestlabs - name: Upgrade provider to a specific pre-release. - text: az tc provider upgrade --base-url https://myurl --name azure.devtestlabs --version v0.1.1 + text: az tc provider upgrade --base-url url --name azure.devtestlabs --version v0.1.1 """ diff --git a/client/tc/azext_tc/_params.py b/client/tc/azext_tc/_params.py index 907e1d8e..12b961ce 100644 --- a/client/tc/azext_tc/_params.py +++ b/client/tc/azext_tc/_params.py @@ -127,10 +127,15 @@ def load_arguments(self, _): options_list=['--role', '-r'], help='User role.') c.argument('properties', properties_type) - for scope in ['tc user create', 'tc user show', 'tc user delete']: + for scope in ['tc user create', 'tc user show', 'tc user delete', 'tc user update']: with self.argument_context(scope) as c: c.argument('user', user_name_or_id_type) + with self.argument_context('tc user update') as c: + c.argument('role', get_enum_type(['None', 'Creator', 'Admin']), + options_list=['--role', '-r'], help='User role.') + c.argument('properties', properties_type) + # Projects with self.argument_context('tc project create') as c: @@ -160,10 +165,16 @@ def load_arguments(self, _): options_list=['--role', '-r'], help='User role.') c.argument('properties', properties_type) - for scope in ['tc project user create', 'tc project user show', 'tc project user delete']: + for scope in ['tc project user create', 'tc project user show', + 'tc project user delete', 'tc project user update']: with self.argument_context(scope) as c: c.argument('user', user_name_or_id_type) + with self.argument_context('tc project user update') as c: + c.argument('role', get_enum_type(['None', 'Member', 'Owner']), + options_list=['--role', '-r'], help='User role.') + c.argument('properties', properties_type) + # Project Types with self.argument_context('tc project-type create') as c: diff --git a/client/tc/azext_tc/commands.py b/client/tc/azext_tc/commands.py index ef4f5544..b121a1ca 100644 --- a/client/tc/azext_tc/commands.py +++ b/client/tc/azext_tc/commands.py @@ -3,6 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- +from azure.cli.core.commands import CliCommandType from ._client_factory import teamcloud_client_factory from ._transformers import (transform_output, transform_user_table_output, transform_project_table_output, transform_project_type_table_output, transform_provider_table_output, @@ -12,6 +13,10 @@ from ._validators import tc_deploy_validator def load_command_table(self, _): + tc_custom = CliCommandType( + operations_tmpl='azext_tc.custom#{}', + client_factory=teamcloud_client_factory) + # TeamCloud with self.command_group('tc', is_preview=True): @@ -32,6 +37,11 @@ def load_command_table(self, _): g.custom_command('list', 'teamcloud_user_list', transform=transform_output, table_transformer=transform_user_table_output) g.custom_show_command('show', 'teamcloud_user_get', transform=transform_output) + g.generic_update_command('update', getter_type=tc_custom, setter_type=tc_custom, + getter_name='teamcloud_user_get_for_update', + setter_name='teamcloud_user_set_for_update', setter_arg_name='payload', + custom_func_name='teamcloud_user_update', + custom_command_type=tc_custom) # TeamCloud Tags @@ -65,6 +75,11 @@ def load_command_table(self, _): g.custom_command('list', 'project_user_list', transform=transform_output, table_transformer=transform_user_table_output) g.custom_show_command('show', 'project_user_get', transform=transform_output) + g.generic_update_command('update', getter_type=tc_custom, setter_type=tc_custom, + getter_name='project_user_get_for_update', + setter_name='project_user_set_for_update', setter_arg_name='payload', + custom_func_name='project_user_update', + custom_command_type=tc_custom) # Project Tags diff --git a/client/tc/azext_tc/custom.py b/client/tc/azext_tc/custom.py index 54f4108d..8c2faf5b 100644 --- a/client/tc/azext_tc/custom.py +++ b/client/tc/azext_tc/custom.py @@ -143,7 +143,8 @@ def teamcloud_deploy(cmd, client, name, location, resource_group_name='TeamCloud user_definition = UserDefinition(identifier=me, role='Admin', properties=None) _ = client.create_team_cloud_admin_user(user_definition) - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') logger.warning('TeamCloud instance successfully created at: %s', api_url) logger.warning('Use `az configure --defaults tc-base-url=%s` to configure ' 'this as your default TeamCloud instance', api_url) @@ -264,7 +265,8 @@ def teamcloud_upgrade(cmd, client, base_url, resource_group_name='TeamCloud', ve zip_deploy_app(cli_ctx, resource_group_name, api_app_name, api_zip_url) version_string = version or 'the latest version' - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') logger.warning('Successfully upgraded TeamCloud instance to %s', version_string) result = { @@ -311,8 +313,33 @@ def teamcloud_user_get(cmd, client, base_url, user): return client.get_team_cloud_user_by_name_or_id(user) +def teamcloud_user_update(cmd, client, base_url, user, instance, role=None, properties=None): + if role: + instance.role = role + if properties: + instance.properties = instance.properties or {} + instance.properties.update(properties) + for key in [k for k, v in instance.properties.items() if not v]: + instance.properties.pop(key) + return instance + + +def teamcloud_user_get_for_update(cmd, client, base_url, user): + from ._transformers import transform_output + client._client.config.base_url = base_url + instance = client.get_team_cloud_user_by_name_or_id(user) + return transform_output(instance) + + +def teamcloud_user_set_for_update(cmd, client, base_url, payload): + from ._transformers import transform_output + instance = _update_with_status(cmd, client, base_url, payload, client.update_team_cloud_user) + return transform_output(instance) + + # TeamCloud Tags + def teamcloud_tag_create(cmd, client, base_url, tag_key, tag_value, no_wait=False): payload = {tag_key, tag_value} @@ -385,6 +412,34 @@ def project_user_get(cmd, client, base_url, project, user): return client.get_project_user_by_name_or_id(user, project) +def project_user_update(cmd, client, base_url, project, user, instance, role=None, properties=None): + index = next((i for i, m in enumerate(instance.project_memberships) + if m.project_id == project), None) + if role: + instance.project_memberships[index].role = role + if properties: + instance.project_memberships[index].properties = instance.project_memberships[ + index].properties or {} + instance.project_memberships[index].properties.update(properties) + for key in [k for k, v in instance.project_memberships[index].properties.items() if not v]: + instance.project_memberships[index].properties.pop(key) + return instance + + +def project_user_get_for_update(cmd, client, base_url, project, user): + from ._transformers import transform_output + client._client.config.base_url = base_url + instance = client.get_project_user_by_name_or_id(user, project) + return transform_output(instance) + + +def project_user_set_for_update(cmd, client, base_url, project, payload): + from ._transformers import transform_output + instance = _update_with_status(cmd, client, base_url, payload, client.update_project_user, + project_id=project) + return transform_output(instance) + + # Project Tags def project_tag_create(cmd, client, base_url, project, tag_key, tag_value, no_wait=False): @@ -687,14 +742,15 @@ def _create_with_status(cmd, client, base_url, payload, create_func, hook = cmd.cli_ctx.get_progress_controller() if hook_start: - hook.begin() - hook.add(message='Creating new {}'.format(type_name)) + hook.begin(message='Starting: Creating new {}'.format(type_name)) + hook.add(message='Starting: Creating new {}'.format(type_name)) result = create_func(project_id, payload) if project_id else create_func(payload) while isinstance(result, StatusResult): if result.code == 200: - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') return result if result.code == 202: @@ -715,7 +771,8 @@ def _create_with_status(cmd, client, base_url, payload, create_func, else: result = client.get_status(result._tracking_id) - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') return result @@ -733,15 +790,15 @@ def _update_with_status(cmd, client, base_url, payload, update_func, hook = cmd.cli_ctx.get_progress_controller() if hook_start: - hook.begin() - - hook.add(message='Updating {}'.format(type_name)) + hook.begin(message='Starting: Updating {}'.format(type_name)) + hook.add(message='Starting: Updating {}'.format(type_name)) result = update_func(project_id, payload) if project_id else update_func(payload) while isinstance(result, StatusResult): if result.code == 200: - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') return result if result.code == 202: @@ -762,7 +819,8 @@ def _update_with_status(cmd, client, base_url, payload, update_func, else: result = client.get_status(result._tracking_id) - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') return result @@ -780,14 +838,15 @@ def _delete_with_status(cmd, client, base_url, item_id, delete_func, hook = cmd.cli_ctx.get_progress_controller() if hook_start: - hook.begin() - hook.add(message='Deleting {}'.format(type_name)) + hook.begin(message='Starting: Deleting {}'.format(type_name)) + hook.add(message='Starting: Deleting {}'.format(type_name)) result = delete_func(item_id, project_id) if project_id else delete_func(item_id) while isinstance(result, StatusResult): if result.code == 200: - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') return result if result.code == 202: @@ -808,6 +867,7 @@ def _delete_with_status(cmd, client, base_url, item_id, delete_func, else: result = client.get_status(result._tracking_id) - hook.end(message='\n') + hook.end(message=' ') + logger.warning(' ') return result diff --git a/client/tc/setup.py b/client/tc/setup.py index 53d1eddc..df8cfafc 100644 --- a/client/tc/setup.py +++ b/client/tc/setup.py @@ -15,7 +15,7 @@ except ImportError: logger.warn("Wheel is not available, disabling bdist_wheel hook") # Must match a HISTORY.rst entry. -VERSION = '0.5.1' +VERSION = '0.5.2' # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers diff --git a/linter_exclusions.yml b/linter_exclusions.yml new file mode 100644 index 00000000..53f95b28 --- /dev/null +++ b/linter_exclusions.yml @@ -0,0 +1,10 @@ +tc user update: + parameters: + base_url: + rule_exclusions: + - no_parameter_defaults_for_update_commands +tc project user update: + parameters: + base_url: + rule_exclusions: + - no_parameter_defaults_for_update_commands \ No newline at end of file