Skip to content

Commit

Permalink
Pipeline variables and variable group management commands (#711)
Browse files Browse the repository at this point in the history
* Variable group management commands

* Pipeline Variable commands
  • Loading branch information
atbagga committed Jul 19, 2019
1 parent cbf2503 commit da104f9
Show file tree
Hide file tree
Showing 13 changed files with 9,644 additions and 10 deletions.
1 change: 1 addition & 0 deletions azure-devops/azext_devops/dev/common/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
CLI_ENV_VARIABLE_PREFIX = 'AZURE_DEVOPS_EXT_'
AZ_DEVOPS_CONFIG_DIR_ENVKEY = CLI_ENV_VARIABLE_PREFIX + 'CONFIG_DIR'
AZ_DEVOPS_GITHUB_PAT_ENVKEY = CLI_ENV_VARIABLE_PREFIX + 'GITHUB_PAT'
AZ_DEVOPS_PIPELINES_VARIABLES_KEY_PREFIX = CLI_ENV_VARIABLE_PREFIX + 'PIPELINE_VAR_'

# Import request Environment Variable
GIT_SOURCE_PASSWORD_OR_PAT = CLI_ENV_VARIABLE_PREFIX + 'GIT_SOURCE_PASSWORD_OR_PAT'
Expand Down
63 changes: 63 additions & 0 deletions azure-devops/azext_devops/dev/pipelines/_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from collections import OrderedDict
import dateutil

_VALUE_TRUNCATION_LENGTH = 80


def transform_builds_table_output(result):
table_output = []
Expand Down Expand Up @@ -300,3 +302,64 @@ def _transform_pipeline_queue_row(row):
table_row['Pool IsHosted'] = row['pool']['isHosted']
table_row['Pool Type'] = row['pool']['poolType']
return table_row


def transform_pipelines_variable_groups_table_output(result):
table_output = []
for item in result:
table_output.append(_transform_pipeline_variable_group_row(item))
return table_output


def transform_pipelines_variable_group_table_output(result):
table_output = [_transform_pipeline_variable_group_row(result)]
return table_output


def _transform_pipeline_variable_group_row(row):
table_row = OrderedDict()
table_row['ID'] = row['id']
table_row['Name'] = row['name']
table_row['Type'] = row['type']
table_row['Description'] = row['description']
if row.get('authorized', None) is not None:
table_row['Is Authorized'] = row['authorized']
table_row['Number of Variables'] = len(row['variables'])
return table_row


def transform_pipelines_variables_table_output(result):
table_output = []
for key, value in result.items():
table_output.append(_transform_pipeline_variable_row(key, value))
return table_output


def _transform_pipeline_variable_row(key, value):
table_row = OrderedDict()
table_row['Name'] = key
table_row['Allow Override'] = 'True' if value['allowOverride'] else 'False'
table_row['Is Secret'] = 'True' if value['isSecret'] else 'False'
val = value['value'] if value['value'] is not None else ''
if len(val) > _VALUE_TRUNCATION_LENGTH:
val = val[0:_VALUE_TRUNCATION_LENGTH] + '...'
table_row['Value'] = val
return table_row


def transform_pipelines_var_group_variables_table_output(result):
table_output = []
for key, value in result.items():
table_output.append(_transform_pipeline_var_group_variable_row(key, value))
return table_output


def _transform_pipeline_var_group_variable_row(key, value):
table_row = OrderedDict()
table_row['Name'] = key
table_row['Is Secret'] = 'True' if value['isSecret'] else 'False'
val = value['value'] if value['value'] is not None else ''
if len(val) > _VALUE_TRUNCATION_LENGTH:
val = val[0:_VALUE_TRUNCATION_LENGTH] + '...'
table_row['Value'] = val
return table_row
18 changes: 18 additions & 0 deletions azure-devops/azext_devops/dev/pipelines/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ def load_pipelines_help():
long-summary:
"""

helps['pipelines variable-group'] = """
type: group
short-summary: (PREVIEW) Manage variable groups.
long-summary:
"""

helps['pipelines variable-group variable'] = """
type: group
short-summary: (PREVIEW) Manage variables in a variable group.
long-summary:
"""

helps['pipelines pool'] = """
type: group
short-summary: (PREVIEW) Manage agent pools.
Expand All @@ -49,6 +61,12 @@ def load_pipelines_help():
long-summary:
"""

helps['pipelines variable'] = """
type: group
short-summary: (PREVIEW) Manage pipeline variables.
long-summary:
"""

helps['pipelines build tag'] = """
type: group
short-summary: Manage build tags.
Expand Down
28 changes: 25 additions & 3 deletions azure-devops/azext_devops/dev/pipelines/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@

_AGENT_POOL_TYPES = ['automation', 'deployment']

_AGENT_ACTION_FILTER_TYPES = ['use', 'manage', 'none']
_ACTION_FILTER_TYPES = ['use', 'manage', 'none']

_VAR_GROUPS_QUERY_ORDER = ['Asc', 'Desc']


# pylint: disable=too-many-statements
def load_build_arguments(self, _):
with self.argument_context('pipelines build list') as context:
context.argument('definition_ids', nargs='*', type=int)
Expand Down Expand Up @@ -74,10 +77,14 @@ def load_build_arguments(self, _):

with self.argument_context('pipelines create') as context:
context.argument('repository_type', choices=['tfsgit', 'github'], type=str.lower)
context.argument('yml_path', options_list=('--yml-path', '--yaml-path'))

with self.argument_context('pipelines update') as context:
context.argument('yml_path', options_list=('--yml-path', '--yaml-path'))

with self.argument_context('pipelines pool') as context:
context.argument('pool_id', options_list=('--pool-id', '--id'))
context.argument('action', **enum_choice_list(_AGENT_ACTION_FILTER_TYPES))
context.argument('action', **enum_choice_list(_ACTION_FILTER_TYPES))
context.argument('pool_type', **enum_choice_list(_AGENT_POOL_TYPES))

with self.argument_context('pipelines agent') as context:
Expand All @@ -88,4 +95,19 @@ def load_build_arguments(self, _):

with self.argument_context('pipelines queue') as context:
context.argument('queue_id', options_list=('--queue-id', '--id'))
context.argument('action', **enum_choice_list(_AGENT_ACTION_FILTER_TYPES))
context.argument('action', **enum_choice_list(_ACTION_FILTER_TYPES))

with self.argument_context('pipelines variable-group') as context:
context.argument('group_id', options_list=('--group-id', '--id'))
context.argument('variables', nargs='*')
context.argument('query_order', **enum_choice_list(_VAR_GROUPS_QUERY_ORDER))
context.argument('action_filter', options_list=('--action-filter', '--action'),
**enum_choice_list(_ACTION_FILTER_TYPES))
context.argument('secret', arg_type=get_three_state_flag())
context.argument('authorize', arg_type=get_three_state_flag())
context.argument('prompt_value', arg_type=get_three_state_flag())

with self.argument_context('pipelines variable') as context:
context.argument('secret', arg_type=get_three_state_flag())
context.argument('prompt_value', arg_type=get_three_state_flag())
context.argument('allow_override', arg_type=get_three_state_flag())
42 changes: 41 additions & 1 deletion azure-devops/azext_devops/dev/pipelines/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
transform_pipelines_agents_table_output,
transform_pipelines_agent_table_output,
transform_pipelines_queues_table_output,
transform_pipelines_queue_table_output)
transform_pipelines_queue_table_output,
transform_pipelines_variable_groups_table_output,
transform_pipelines_variable_group_table_output,
transform_pipelines_variables_table_output,
transform_pipelines_var_group_variables_table_output)

buildOps = CliCommandType(
operations_tmpl='azext_devops.dev.pipelines.build#{}',
Expand Down Expand Up @@ -76,7 +80,18 @@
exception_handler=azure_devops_exception_handler
)

pipelineVariableGroupOps = CliCommandType(
operations_tmpl='azext_devops.dev.pipelines.variable_group#{}',
exception_handler=azure_devops_exception_handler
)

pipelineVariablesOps = CliCommandType(
operations_tmpl='azext_devops.dev.pipelines.pipeline_variables#{}',
exception_handler=azure_devops_exception_handler
)


# pylint: disable=too-many-statements
def load_build_commands(self, _):
with self.command_group('pipelines', command_type=pipelineCreateOps) as g:
g.command('create', 'pipeline_create', table_transformer=transform_pipeline_run_table_output)
Expand Down Expand Up @@ -141,3 +156,28 @@ def load_build_commands(self, _):
with self.command_group('pipelines queue', command_type=pipelineAgentPoolQueueOps) as g:
g.command('list', 'list_queues', table_transformer=transform_pipelines_queues_table_output)
g.command('show', 'show_queue', table_transformer=transform_pipelines_queue_table_output)

with self.command_group('pipelines variable-group', command_type=pipelineVariableGroupOps) as g:
g.command('create', 'variable_group_create', table_transformer=transform_pipelines_variable_group_table_output)
g.command('show', 'variable_group_show', table_transformer=transform_pipelines_variable_group_table_output)
g.command('list', 'variable_group_list', table_transformer=transform_pipelines_variable_groups_table_output)
g.command('update', 'variable_group_update', table_transformer=transform_pipelines_variable_group_table_output)
g.command('delete', 'variable_group_delete',
confirmation='Are you sure you want to delete this variable group?')

with self.command_group('pipelines variable-group variable', command_type=pipelineVariableGroupOps) as g:
g.command('create', 'variable_group_variable_add',
table_transformer=transform_pipelines_var_group_variables_table_output)
g.command('list', 'variable_group_variable_list',
table_transformer=transform_pipelines_var_group_variables_table_output)
g.command('update', 'variable_group_variable_update',
table_transformer=transform_pipelines_var_group_variables_table_output)
g.command('delete', 'variable_group_variable_delete',
confirmation='Are you sure you want to delete this variable?')

with self.command_group('pipelines variable', command_type=pipelineVariablesOps) as g:
g.command('create', 'pipeline_variable_add', table_transformer=transform_pipelines_variables_table_output)
g.command('update', 'pipeline_variable_update', table_transformer=transform_pipelines_variables_table_output)
g.command('list', 'pipeline_variable_list', table_transformer=transform_pipelines_variables_table_output)
g.command('delete', 'pipeline_variable_delete',
confirmation='Are you sure you want to delete this variable?')
12 changes: 6 additions & 6 deletions azure-devops/azext_devops/dev/pipelines/pipeline_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

# pylint: disable=too-few-public-methods
class YmlOptions:
def __init__(self, name, id, content, description='Custom yml', params=None, path=None, assets=None): # pylint: disable=redefined-builtin
def __init__(self, name, id, content, description='Custom yaml', params=None, path=None, assets=None): # pylint: disable=redefined-builtin
self.name = name
self.id = id
self.description = description
Expand Down Expand Up @@ -61,7 +61,7 @@ def pipeline_create(name, description=None, repository=None, branch=None, yml_pa
:param branch: Branch name for which the pipeline will be configured. If omitted, it will be auto-detected
from local repository
:type branch: str
:param yml_path: Path of the pipelines yml file in the repo (if yml is already present in the repo).
:param yml_path: Path of the pipelines yaml file in the repo (if yaml is already present in the repo).
:type yml_path: str
:param repository_type: Type of repository. If omitted, it will be auto-detected from remote url
of local repository. 'tfsgit' for Azure Repos, 'github' for GitHub repository.
Expand Down Expand Up @@ -157,7 +157,7 @@ def pipeline_update(name=None, id=None, description=None, new_name=None, # pyli
:type description: str
:param branch: Branch name for which the pipeline will be configured.
:type branch: str
:param yml_path: Path of the pipelines yml file in the repo.
:param yml_path: Path of the pipelines yaml file in the repo.
:type yml_path: str
:param queue_id: Queue id of the agent pool where the pipeline needs to run.
:type queue_id: int
Expand Down Expand Up @@ -266,7 +266,7 @@ def try_get_repository_type(url):

def _create_and_get_yml_path(cix_client, repository_type, repo_id, repo_name, branch, # pylint: disable=too-many-locals, too-many-statements
service_endpoint, project, organization):
logger.debug('No yml file was given. Trying to find the yml file in the repo.')
logger.debug('No yaml file was given. Trying to find the yaml file in the repo.')
queue_branch = branch
default_yml_exists = False
yml_names = []
Expand All @@ -277,8 +277,8 @@ def _create_and_get_yml_path(cix_client, repository_type, repo_id, repo_name, br
for configuration in configurations:
if configuration.path.strip('/') == 'azure-pipelines.yml':
default_yml_exists = True
logger.debug('The repo has a yml pipeline definition. Path: %s', configuration.path)
custom_name = 'Existing yml (path={})'.format(configuration.path)
logger.debug('The repo has a yaml pipeline definition. Path: %s', configuration.path)
custom_name = 'Existing yaml (path={})'.format(configuration.path)
yml_names.append(custom_name)
yml_options.append(YmlOptions(name=custom_name, content=configuration.content, id='customid',
path=configuration.path))
Expand Down
36 changes: 36 additions & 0 deletions azure-devops/azext_devops/dev/pipelines/pipeline_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from azext_devops.dev.common.services import get_build_client
from azext_devops.devops_sdk.v5_0.build.models import DefinitionResourceReference


def set_authorize_resource(authorized, res_id, name, res_type, organization, project):
"""
param authorized: Boolean value set to authorize or unauthorize resource
param id: Id of the resource to authorize
param name: Name of the resource to authorize
param type: Type of the resource to authorize
param organization: Organization URL
param project: Project Id
"""
client = get_build_client(organization=organization)
resources = [DefinitionResourceReference(authorized=authorized, id=res_id, name=name, type=res_type)]
client.authorize_project_resources(resources=resources, project=project)


def get_authorize_resource(res_id, res_type, organization, project):
"""
param id: Id of the resource to authorize
param name: Name of the resource to authorize
param type: Type of the resource to authorize
param organization: Organization URL
param project: Project Id
"""
client = get_build_client(organization=organization)
resource = client.get_project_resources(project=project, id=res_id, type=res_type)
if resource:
return resource[0].authorized
return None
Loading

0 comments on commit da104f9

Please sign in to comment.