fn run_sub_task_and_report(
    flow_info: &FlowInfo,
    flow_state: Rc<RefCell<FlowState>>,
    sub_task: &RunTaskInfo,
) -> Result<bool, CargoMakeError> {
    let (task_names, fork, parallel, cleanup_task) = match sub_task {
        RunTaskInfo::Name(ref name) => (Some(vec![name.to_string()]), false, false, None),
        RunTaskInfo::Details(ref details) => {
            let task_name_values = match details.name.clone() {
                RunTaskName::Single(name) => vec![name],
                RunTaskName::Multiple(names) => names,
            };
            (
                Some(task_name_values),
                details.fork.unwrap_or(false),
                details.parallel.unwrap_or(false),
                details.cleanup_task.clone(),
            )
        }
        RunTaskInfo::Routing(ref routing_info) => {
            get_sub_task_info_for_routing_info(&flow_info, routing_info)?
        }
    };

    if task_names.is_some() {
        let names = task_names.unwrap();
        let mut threads = vec![];

        // clean up task only supported for forked tasks
        if !fork && cleanup_task.is_some() {
            error!("Invalid task, cannot use cleanup_task without fork.");
        }

        for name in names {
            let task_run_fn = move |flow_info: &FlowInfo,
                                    flow_state: Rc<RefCell<FlowState>>,
                                    fork: bool,
                                    cleanup_task: &Option<String>|
                  -> Result<(), CargoMakeError> {
                let mut sub_flow_info = flow_info.clone();
                sub_flow_info.task = name;

                if fork {
                    run_forked_task(&sub_flow_info, flow_state, cleanup_task)
                } else {
                    run_flow(&sub_flow_info, flow_state, true)
                }
            };

            if parallel {
                let run_flow_info = flow_info.clone();
                // we do not support merging changes back to parent
                let cloned_flow_state = flow_state.borrow().clone();
                let cloned_cleanup_task = cleanup_task.clone();
                threads.push(thread::spawn(move || -> Result<(), CargoMakeError> {
                    task_run_fn(
                        &run_flow_info,
                        Rc::new(RefCell::new(cloned_flow_state)),
                        fork,
                        &cloned_cleanup_task,
                    )
                }));
            } else {
                task_run_fn(&flow_info, flow_state.clone(), fork, &cleanup_task)?;
            }
        }

        if threads.len() > 0 {
            for task_thread in threads {
                task_thread.join().unwrap()?;
            }
        }

        if let Some(cleanup_task_name) = cleanup_task {
            run_cleanup_task(&flow_info, flow_state, &cleanup_task_name)?;
        }

        Ok(true)
    } else {
        Ok(false)
    }
}
runs a sub task and returns true/false based if a sub task was actually invoked
src/lib/runner.rs