def plan_repo_add(config, plan_id, repo): api_client = ApiClient(config) # Look up the plan plan = get_plan(api_client, plan_id) # Filter by repository repo_data = lookup_repo(api_client, config, repo, required=True) # Check that we don't already have a matching PlanRepository params = { 'plan': plan_id, 'repo': repo_data['id'], } res = api_client('plan_repos', 'list', params=params) if res['count']: raise click.ClickException('Repo already added to plan') # Create the PlanRepository params = { 'plan_id': plan_id, 'repo_id': repo_data['id'], } res = api_client('plan_repos', 'create', params=params) click.echo() click.echo( 'Added repo {repo[owner]}/{repo[name]} to plan {plan[name]}'.format( **res)) render_recursive(res)
def build_info(config, build_id, log, flow_log, flow): api_client = ApiClient(config) params = { 'id': build_id, } # Look up the build try: build_res = api_client('builds', 'read', params=params) except coreapi.exceptions.ErrorMessage as e: raise click.ClickException( 'Build with id {} not found. Use metaci build list to see a list of latest builds and their ids' .format(build_id)) if log: click.echo(build_res['log']) elif flow_log: params = {'build': build_id} if flow: params['flow'] = flow build_flow_res = api_client('build_flows', 'list', params=params) for build_flow in build_flow_res['results']: click.echo() click.echo( click.style('{}:'.format(build_flow['flow']), bold=True, fg='blue')) click.echo(build_flow['log']) else: click.echo(render_recursive(build_res))
def org_list(config, repo): api_client = ApiClient(config) params = {} # Filter by repository repo_data = lookup_repo(api_client, config, repo) if repo_data: params['repo'] = repo_data['id'] res = api_client('orgs', 'list', params=params) org_list_fmt = '{id:<5} {name:24.24} {scratch:7} {repo[owner]}' headers = { 'id': '#', 'name': 'Name', 'scratch': 'Scratch', 'repo': { 'owner': 'Repo' }, } click.echo(org_list_fmt.format(**headers)) #org_list_fmt += "/{repo[name]}" for org in res['results']: click.echo(org_list_fmt.format(**org))
def build_list(config, repo, status): api_client = ApiClient(config) params = {} # Filter by repository repo_data = lookup_repo(api_client, config, repo) if repo_data: params['repo'] = repo_data['id'] # Filter by status if status: params['status'] = status res = api_client('builds', 'list', params=params) build_list_fmt = '{id:<5} {status:8.8} {plan[name]:24.24} {branch[name]:24.24} {commit}' headers = { 'id': '#', 'status': 'Status', 'plan': { 'name': 'Plan' }, 'branch': { 'name': 'Branch' }, 'commit': 'Commit', } click.echo(build_list_fmt.format(**headers)) for build in res['results']: click.echo( color_status( status=build['status'], line=build_list_fmt.format(**build), ))
def org_add(config, name, org, repo): require_project_config(config) api_client = ApiClient(config) params = {} # Prompt for org name if not specified if not org: click.echo( 'To create a MetaCI org, select one of your existing CumulusCI orgs. The org information from your local CumulusCI keychain will be transferred to the MetaCI site. You can use cci org scratch or cci org connect to create new CumulusCI orgs if needed.' ) click.echo() default_org, org_config = config.keychain.get_default_org() click.echo('Available Orgs: ' + ', '.join(config.keychain.list_orgs())) org = click.prompt('Org', default=default_org) # Validate the org try: org_config = config.keychain.get_org(org) except OrgNotFound: raise click.ClickException( 'The org {} is not configured in the local cci keychain'.format( org)) org_name = name if not name: org_name = org # Filter by repository repo_data = lookup_repo(api_client, config, repo, required=True) name = prompt_org_name(repo_data['id'], org_name, api_client) params['repo_id'] = repo_data['id'] params['name'] = name params['scratch'] = isinstance(org_config, ScratchOrgConfig) if params['scratch']: clean_org_config = { 'config_file': org_config.config_file, 'config_name': org_config.config_name, 'namespaced': org_config.namespaced, 'scratch': org_config.scratch, } else: clean_org_config = org_config.config params['json'] = json.dumps(clean_org_config) res = api_client('orgs', 'create', params=params) click.echo() click.echo( 'Org {} was successfully created. Use metaci org info {} to see the org details.' .format(name, name))
def service_info(config, name): api_client = ApiClient(config) params = {'name': name} # Look up the service res = api_client('services', 'list', params=params) if res['count'] == 0: raise click.ClickError('Service named {} not found'.format(name)) click.echo(render_recursive(res['results'][0]))
def service_add(config, name): require_project_config(config) api_client = ApiClient(config) services = config.keychain.list_services() existing = [] resp = api_client('services', 'list') for service in resp['results']: existing.append(service['name']) if service['name'] in services: services.remove(service['name']) # Prompt for service name if not specified if not name: click.echo( 'To create a MetaCI service, select one of your existing CumulusCI services. The service information from your local CumulusCI keychain will be transferred to the MetaCI site. You can use cci service list to see available services and cci service connect <service_name> to connect a service to the local cci keychain.' ) click.echo() click.echo('Available Services: ' + ', '.join(services)) name = click.prompt('Service') # Validate the service name if name not in services: if name in existing: raise click.ClickException( 'Service {} already exists. Available services are: {}'. format(name, ', '.join(services))) raise click.ClickException( 'Service {} is invalid. Available services are: {}'.format( name, ', '.join(services))) # Validate the service exists in the cci keychain try: service_config = config.keychain.get_service(name) except ServiceNotConfigured: raise click.ClickException( 'The service {} is not configured in the local cci keychain. Use cci service connect {}' .format(service, service)) except ServiceNotValid: raise click.ClickException( 'The service {} is not a valid cci service name. If this is a custom service for the project, you need to first configure the service in the project cumulusci.yml file.' .format(service)) params = {} params['name'] = name params['json'] = json.dumps(service_config.config) res = api_client('services', 'create', params=params) click.echo() click.echo( 'Service {} was successfully created. Use metaci service info {} to see the service details.' .format(name, name))
def plan_run(config, plan_id, branch, commit): api_client = ApiClient(config) plan = get_plan(api_client, plan_id) # Look up the repo repo_data = lookup_repo(api_client, config, None, required=True) # Look up the plan org org_params = { 'repo': repo_data['id'], 'name': plan['org'], } org_res = api_client('orgs', 'list', params=org_params) if org_res['count'] == 0: raise click.ClickException( 'The plan org "{}" does not exist in MetaCI. Use metaci org create to create the org.' .format(plan['org'])) org_data = org_res['results'][0] # Look up the branch if not branch: branch = config.project_config.repo_branch branch_data = get_or_create_branch(api_client, branch, repo_data['id']) # Determine the commit if not commit: gh = config.project_config.get_github_api() gh_repo = gh.repository( config.project_config.repo_owner, config.project_config.repo_name, ) branch = gh_repo.branch(branch) commit = branch.commit.sha # Create the build build_params = { 'repo_id': repo_data['id'], 'org_id': org_data['id'], 'plan_id': plan_id, 'branch_id': branch_data['id'], 'commit': commit, } resp = api_client('builds', 'create', params=build_params) click.echo( click.style('Build {} created successfully'.format(resp['id']), bold=True, fg='green')) click.echo( 'Use metaci build info {} to monitor the build or metaci build list to monitor multiple builds' .format(resp['id']))
def service_list(config): api_client = ApiClient(config) params = {} res = api_client('services', 'list', params=params) service_list_fmt = '{id:<3} {name}' headers = { 'id': '#', 'name': 'Name', } click.echo(service_list_fmt.format(**headers)) for service in res['results']: click.echo(service_list_fmt.format(**service))
def org_info(config, name, repo): api_client = ApiClient(config) params = {'name': name} # Filter by repository repo_data = lookup_repo(api_client, config, repo, required=True) params['repo'] = repo_data['id'] # Look up the org res = api_client('orgs', 'list', params=params) if res['count'] == 0: raise click.ClickError('Org named {} not found'.format(name)) click.echo(render_recursive(res['results'][0]))
def plan_list(config): api_client = ApiClient(config) res = api_client('plans', 'list') plan_list_fmt = '{id:<5} {name:24.24} {org:12.12} {flows:24.24} {type:7.7} {regex}' headers = { 'id': '#', 'name': 'Status', 'org': 'Org', 'flows': 'Flows', 'type': 'Trigger', 'regex': 'Regex', } click.echo(plan_list_fmt.format(**headers)) for plan in res['results']: click.echo(plan_list_fmt.format(**plan))
def org_browser(config, org_name): api_client = ApiClient(config) params = { 'name': org_name, } # Look up the build res = api_client('orgs', 'list', params=params) if res['count'] == 0: raise click.ClickException( 'Org named {} not found. Use metaci org list to see a list of available org names' .format(org_name)) service = check_current_site(config) url = '{}/orgs/{}'.format(service.url, res['results'][0]['id']) click.echo('Opening browser to {}'.format(url)) webbrowser.open(url)
def service_browser(config, name): api_client = ApiClient(config) params = { 'name': name, } # Look up the build res = api_client('services', 'list', params=params) if res['count'] == 0: raise click.ClickException( 'Service named {} not found. Use metaci service list to see a list of available service names' .format(name)) metaci_service = check_current_site(config) url = '{}/admin/cumulusci/service/{}'.format(metaci_service.url, res['results'][0]['id']) click.echo('Opening browser to {}'.format(url)) webbrowser.open(url)
def build_browser(config, build_id): api_client = ApiClient(config) params = { 'id': build_id, } # Look up the build try: res = api_client('builds', 'read', params=params) except coreapi.exceptions.ErrorMessage as e: raise click.ClickException( 'Build with id {} not found. Use metaci build list to see a list of latest builds and their ids' .format(build_id)) service = check_current_site(config) url = '{}/builds/{}'.format(service.url, res['id']) click.echo('Opening browser to {}'.format(url)) webbrowser.open(url)
def plan_repo_list(config, plan_id): api_client = ApiClient(config) plan = get_plan(api_client, plan_id) params = { 'plan': plan_id, } res = api_client('plan_repos', 'list', params=params) click.echo() click.echo('Repos associated with plan {}:') repo_list_fmt = '{id:<5} {repo[id]:<6} {repo[name]:32.32} {repo[owner]}' headers = { 'id': '#', 'repo': { 'id': 'Repo #', 'name': 'Name', 'owner': 'Owner', }, } click.echo(repo_list_fmt.format(**headers)) for plan_repo in res['results']: click.echo(repo_list_fmt.format(**plan_repo))
def plan_browser(config, plan_id): api_client = ApiClient(config) params = { 'id': plan_id, } # Look up the plan try: res = api_client('plans', 'read', params=params) except coreapi.exceptions.ErrorMessage as e: raise click.ClickException( 'Plan with id {} not found. Use metaci plan list to see a list of plans and their ids' .format(plan_id)) service = check_current_site(config) url = '{}/plans/{}'.format( service.url, res['id'], ) click.echo('Opening browser to {}'.format(url)) webbrowser.open(url)
def plan_add(config): if not config.project_config: raise click.UsageError( 'You must be inside a local git repository configured for CumulusCI. No CumulusCI configuration was detected in the local directory' ) api_client = ApiClient(config) params = {} # Make sure the local repo exists repo_data = lookup_repo(api_client, config, None, required=True) click.echo('# Name and Description') click.echo( 'Provide a name and description of the build plan you are creating') name = click.prompt('Name') description = click.prompt('Description') click.echo() click.echo('# Org') click.echo( 'Select the MetaCI org this plan should run its builds against. If the org does not yet exist, use metaci org create to create the org first.' ) org = prompt_org(api_client, config, repo_data['id']) flows_list = config.project_config.flows.keys() flows_list.sort() click.echo() click.echo('# Flows') click.echo( 'What CumulusCI flows should this plan run? You can enter multiple flows using a comma as a separator' ) click.echo('Available Flows: {}'.format(', '.join(flows_list))) flows = click.prompt('Flow(s)') click.echo() click.echo('# Trigger Type') click.echo('How should this plan be triggered?') click.echo( ' - commit: Trigger on branch commits matching a regex pattern') click.echo(' - tag: Trigger on new tags matching a regex pattern') click.echo( ' - manual: Do not auto-trigger any builds. Can be manually triggered.' ) trigger_type = click.prompt('Trigger Type (commit, tag, or manual)') if trigger_type == 'commit': regex = click.prompt('Branch Match RegEx (ex feature/.*)') elif trigger_type == 'tag': regex = click.prompt('Tag Match RegEx (ex beta/.*)') elif trigger_type != 'manual': raise click.UsageError( '{} is an invalid trigger type. Valid choices are: commit, tag, manual' ) else: regex = None click.echo() click.echo('# Github Commit Status') click.echo( 'MetaCI can set the build status via the Github Commit Status API. Commit statuses are grouped by a context field. Setting a different context on different plans will cause multiple commit statuses to be created for each unique context in Github.' ) context = None if click.confirm('Set commit status in Github for this plan?', default=True): context = click.prompt('Github Commit Status Context', default=name) if trigger_type == 'manual': active = True else: click.echo() click.echo('# Activate Plan') match_str = 'matching regex {}'.format(regex) if regex else '' click.echo( 'If active, this plan will automatically build on new {}s{}'. format(trigger_type, match_str)) active = click.confirm('Active?', default=True) click.echo() click.echo('# Public or Private') click.echo( 'Public plans and their builds are visible to anonymous users. This is recommended for open source projects, instances on an internal network or VPN, or projects that want transparency of their build information. Private plans are only visible to logged in users who have been granted the Is Staff role by an admin.' ) public = click.confirm('Public?') params = { 'name': name, 'description': description, 'org': org, 'flows': flows, 'type': trigger_type, 'regex': regex, 'context': context, 'active': active, 'public': public, } res = api_client('plans', 'create', params=params) click.echo() click.echo( click.style( 'Created plan {} with the following configuration'.format(name), fg='green', )) render_recursive(res) click.echo() click.echo('Adding repository {owner}/{name} to plan'.format(**repo_data)) params = { 'repo_id': repo_data['id'], 'plan_id': res['id'], } res = api_client('plan_repos', 'create', params=params)
def plan_info(config, plan_id): api_client = ApiClient(config) plan = get_plan(api_client, plan_id) click.echo(render_recursive(plan))