Esempio n. 1
0
def cli(ctx, wfile, recursive):
    """
    Creates a graph in the .dot format representing the workflow
    """
    wfile_list = list()
    if recursive:
        wfile_list = pu.find_recursive_wfile()
    else:
        wfile_list.append(pu.find_default_wfile(wfile))

    for wfile in wfile_list:
        pipeline = Workflow(wfile, False, False, False, False)

        graph = list()

        wf = pipeline.wf
        workflow_name = list(wf['workflow'].keys())[0]

        action = wf['resolves'][0]
        last_action = get_first_action(wf)

        for act in last_action:
            graph.append("\t{} -> {};\n".format(
                workflow_name.replace(' ', '_').replace('-', '_'),
                act.replace(' ', '_').replace('-', '_')))

        parent_action = cur_action = action
        graph = add(parent_action, cur_action, wf['action'], graph)
        graph = ''.join(list(set(graph)))
        graph = "digraph G {\n" + graph + "}\n"
        pu.info(graph)
Esempio n. 2
0
    def __init__(self, wfile, workspace, quiet, debug, dry_run):
        wfile = pu.find_default_wfile(wfile)

        with open(wfile, 'r') as fp:
            self.wf = hcl.load(fp)

        self.workspace = workspace
        self.debug = debug
        if debug:
            self.quiet = False
        else:
            self.quiet = quiet
        self.dry_run = dry_run

        self.actions_cache_path = os.path.join('/', 'tmp', 'actions')
        self.validate_syntax()
        self.check_secrets()
        self.normalize()
        self.complete_graph()

        self.env = {
            'GITHUB_WORKSPACE': self.workspace,
            'GITHUB_WORKFLOW': self.wf['name'],
            'GITHUB_ACTOR': 'popper',
            'GITHUB_REPOSITORY': '{}/{}'.format(scm.get_user(),
                                                scm.get_name()),
            'GITHUB_EVENT_NAME': self.wf['on'],
            'GITHUB_EVENT_PATH': '/{}/{}'.format(self.workspace,
                                                 'workflow/event.json'),
            'GITHUB_SHA': scm.get_sha(),
            'GITHUB_REF': scm.get_ref()
        }

        for e in dict(self.env):
            self.env.update({e.replace('GITHUB_', 'POPPER_'): self.env[e]})
Esempio n. 3
0
def cli(ctx, wfile, recursive):
    """
    Creates a graph in the .dot format representing the workflow.
    """
    def add_to_graph(graph_str, wf, parent, children):
        """Recursively goes through "next" and adds corresponding actions
        """
        _parent = parent.replace(' ', '_').replace('-', '_')
        for n in children:
            _n = n.replace(' ', '_').replace('-', '_')
            graph_str += "  {} -> {};\n".format(_parent, _n)
            for M in wf.get_action(n).get('next', []):
                graph_str = add_to_graph(graph_str, wf, n, [M])

        return graph_str

    wfile_list = list()

    if recursive:
        wfile_list = pu.find_recursive_wfile()
    else:
        wfile_list.append(pu.find_default_wfile(wfile))

    for wfile in wfile_list:
        pipeline = WorkflowRunner(wfile, False, False, False, False, True)
        wf = pipeline.wf
        workflow_name = wf.name.replace(' ', '_').replace('-', '_')
        graph_str = add_to_graph("", wf, workflow_name, wf.root)
        log.info("digraph G {\n" + graph_str + "}\n")
Esempio n. 4
0
def run_workflow(**kwargs):

    kwargs['wfile'] = pu.find_default_wfile(kwargs['wfile'])
    log.info('Found and running workflow at ' + kwargs['wfile'])
    # Initialize a Worklow. During initialization all the validation
    # takes place automatically.
    wf = Workflow(kwargs['wfile'])
    wf_runner = WorkflowRunner(wf)

    # Check for injected actions
    pre_wfile = os.environ.get('POPPER_PRE_WORKFLOW_PATH')
    post_wfile = os.environ.get('POPPER_POST_WORKFLOW_PATH')

    # Saving workflow instance for signal handling
    popper.cli.interrupt_params['parallel'] = kwargs['parallel']

    if kwargs['parallel']:
        if sys.version_info[0] < 3:
            log.fail('--parallel is only supported on Python3')
        log.warning("Using --parallel may result in interleaved output. "
                    "You may use --quiet flag to avoid confusion.")

    if kwargs['with_dependencies'] and (not kwargs['action']):
        log.fail('`--with-dependencies` can be used only with '
                 'action argument.')

    if kwargs['skip'] and kwargs['action']:
        log.fail('`--skip` can\'t be used when action argument ' 'is passed.')

    on_failure = kwargs.pop('on_failure')
    wfile = kwargs.pop('wfile')

    try:
        if pre_wfile:
            pre_wf = Workflow(pre_wfile)
            pre_wf_runner = WorkflowRunner(pre_wf)
            pre_wf_runner.run(**kwargs)

        wf_runner.run(**kwargs)

        if post_wfile:
            post_wf = Workflow(post_wfile)
            pre_wf_runner = WorkflowRunner(post_wf)
            pre_wf_runner.run(**kwargs)

    except SystemExit as e:
        if (e.code != 0) and on_failure:
            kwargs['skip'] = list()
            kwargs['action'] = on_failure
            wf_runner.run(**kwargs)
        else:
            raise

    if kwargs['action']:
        log.info('Action "{}" finished successfully.'.format(kwargs['action']))
    else:
        log.info('Workflow "{}" finished successfully.'.format(wfile))
    def test_find_default_wfile(self):
        os.makedirs('/tmp/test_folder/.github')
        os.chdir('/tmp/test_folder')

        self.assertRaises(SystemExit, pu.find_default_wfile, None)
        self.assertRaises(SystemExit, pu.find_default_wfile, 'a.workflow')
        self.touch_file('/tmp/test_folder/.github/main.workflow')
        wfile = pu.find_default_wfile()
        self.assertEqual(wfile, '.github/main.workflow')

        shutil.rmtree('/tmp/test_folder')
Esempio n. 6
0
    def __init__(self, wfile, workspace, dry_run,
                 reuse, parallel, skip_secrets_prompt=False):

        wfile = pu.find_default_wfile(wfile)

        self.workspace = workspace
        self.dry_run = dry_run
        self.reuse = reuse
        self.parallel = parallel
        self.skip_secrets_prompt = skip_secrets_prompt
        self.actions_cache_path = os.path.join('/', 'tmp', 'actions')

        # Initialize a Worklow. During initialization all the validation
        # takes place automatically.
        self.wf = Workflow(wfile)
        self.check_secrets()
        log.debug('workflow:\n{}'.format(
            yaml.dump(self.wf, default_flow_style=False, default_style='')))
Esempio n. 7
0
def cli(ctx, wfile, skip, recursive, colors):
    """
    Creates a graph in the .dot format representing the workflow.
    """
    def add_to_graph(dot_str, wf, parent, children, node_attrs, stage_edges):
        """Recursively goes over the children ("next" attribute) of the given
        parent, adding an edge from parent to children
        """
        for n in children:
            edge = '  "{}" -> "{}";\n'.format(parent, n)
            if edge in stage_edges:
                continue
            dot_str += edge + '  "{}" [{}];\n'.format(n, node_attrs)

            stage_edges.add(edge)

            for M in wf.get_action(n).get('next', []):
                dot_str = add_to_graph(dot_str, wf, n, [M], node_attrs,
                                       stage_edges)
        return dot_str

    wfile_list = list()

    if recursive:
        wfile_list = pu.find_recursive_wfile()
    else:
        wfile_list.append(pu.find_default_wfile(wfile))

    for wfile in wfile_list:
        wf = Workflow(wfile)
        wf.parse()
        wf = Workflow.skip_actions(wf, skip)
        wf.check_for_unreachable_actions()

        node_attrs = ('shape=box, style="filled{}", fillcolor=transparent{}')
        wf_attr = node_attrs.format(',rounded', ',color=red' if colors else '')
        act_attr = node_attrs.format('', ',color=cyan' if colors else '')
        dot_str = add_to_graph("", wf, wf.name, wf.root, act_attr, set())
        dot_str += '  "{}" [{}];\n'.format(wf.name, wf_attr)
        log.info("digraph G { graph [bgcolor=transparent];\n" + dot_str +
                 "}\n")
Esempio n. 8
0
def cli(ctx, action, wfile, skip_clone, skip_pull, skip, workspace, reuse,
        recursive, quiet, debug, dry_run, parallel, log_file,
        with_dependencies, on_failure):
    """Executes one or more pipelines and reports on their status.
    """
    popper.scm.get_git_root_folder()
    level = 'ACTION_INFO'
    if quiet:
        level = 'INFO'
    if debug:
        level = 'DEBUG'
    log.setLevel(level)
    if log_file:
        logging.add_log(log, log_file)

    if os.environ.get('CI') == 'true':
        log.info("Running in CI environment.")
        if recursive:
            log.warning('When CI variable is set, --recursive is ignored.')
        wfile_list = pu.find_recursive_wfile()
        wfile_list = workflows_from_commit_message(wfile_list)
    else:
        if recursive:
            if action:
                log.fail(
                    "An 'action' argument and the --recursive flag cannot be "
                    "both given.")
            wfile_list = pu.find_recursive_wfile()
        else:
            wfile_list = [wfile]

    if not wfile_list:
        log.fail("No workflow to execute.")

    for wfile in wfile_list:
        wfile = pu.find_default_wfile(wfile)
        log.info("Found and running workflow at " + wfile)
        run_pipeline(action, wfile, skip_clone, skip_pull, skip, workspace,
                     reuse, dry_run, parallel, with_dependencies, on_failure)