def generate_circle_output():
    """Build sequence for Circle CI 2.0 config.yml

    builds the circleci structure
    also links individual jobs into a workflow graph
    """
    base = new_base()
    workflow = networkx.DiGraph()
    LOG.info('%s python versions', len(python_versions))
    LOG.info('%s mbed cloud hosts', len(mbed_cloud_hosts))

    job, content = new_tpip()
    base['jobs'].update({job: content})
    workflow.add_node(job)

    job, content = new_newscheck()
    base['jobs'].update({job: content})
    workflow.add_node(
        job,
        workflow=dict(
            filters=dict(
                branches=dict(
                    # we ignore this check for builds directly on the base branches
                    ignore=['master', 'integration']
                )
            )
        )
    )

    job, content = new_build_documentation()
    base['jobs'].update({job: content})
    workflow.add_node(
        job,
        workflow=dict(
            requires=['build_py2', 'build_py3'],
            filters = dict(
                branches=dict(
                    # Only update the documentation on release branches
                    only=['master', 'beta']
        )
    )
    )
    )

    preload_job, content = new_preload()
    base['jobs'].update({preload_job: content})
    workflow.add_node(job)

    for py_ver in python_versions.values():
        build_job, build_content = new_build(py_ver=py_ver)
        base['jobs'].update({build_job: build_content})
        workflow.add_edge(preload_job, build_job)

        for cloud_host in mbed_cloud_hosts.values():
            test_job, test_content = new_test(py_ver=py_ver, cloud_host=cloud_host)
            base['jobs'].update({test_job: test_content})
            workflow.add_edge(build_job, test_job)

    for release_target in release_target_map.values():
        deploy_job, deploy_content = new_deploy(
            py_ver=python_versions['three'],
            release_target=release_target
        )
        base['jobs'].update({deploy_job: deploy_content})

    # wire up the release gates (clicky buttons)
    workflow.add_edge(
        test_name(python_versions['three'], mbed_cloud_hosts['osii']),
        release_name(release_target_map['beta']),
        type='approval',
    )
    workflow.add_edge(
        test_name(python_versions['three'], mbed_cloud_hosts['production']),
        release_name(release_target_map['prod']),
        type='approval',
        filters=dict(branches=dict(only='master')),
    )
    workflow.add_edge(
        test_name(python_versions['two'], mbed_cloud_hosts['production']),
        release_name(release_target_map['prod']),
    )

    # we only want to deploy in certain conditions
    workflow.add_edge(
        release_name(release_target_map['beta']),
        deploy_name(python_versions['three'], release_target_map['beta'])
    )

    workflow.add_edge(
        release_name(release_target_map['prod']),
        deploy_name(python_versions['three'], release_target_map['prod'])
    )

    workflow_jobs = base['workflows']['python_sdk_workflow']['jobs']

    # build the workflow graph
    for job_name in networkx.topological_sort(workflow):
        job_config = {}
        per_node_config = workflow.nodes[job_name].get('workflow')
        if per_node_config:
            job_config.update(per_node_config)
        workflow_jobs.append({job_name: job_config})
        for edge in workflow.in_edges(job_name):
            job_config.update(workflow.get_edge_data(*edge))
            job_config.setdefault('requires', []).append(edge[0])

    LOG.info('%s circle jobs', len(base['jobs']))
    return dict(base)