anchor.diff:    }
   }
   
  -class Exec extends Command {
  +class Exec extends BaseJefeCommand {
     final name = "exec";
     final description = 'Runs the given command in all projects';
   
     Exec() {
       argParser.addOption('command', help: 'The command to execute', abbr: 'c');
  -    argParser.addOption('rootDirectory',
  -        help: 'The directory that contains the root of the projecs',
  -        abbr: 'd',
  -        defaultsTo: '.');
  -    argParser.addOption('projects',
  -        help:
  -            'A project name filter. Only projects whose name contains the text will run',
  -        abbr: 'p');
  +    addRootDirectory();
  +    addProjects();
       argParser.addFlag('executeSerially',
           help:
  -            'Instead of running the commands concurrently on the projects, run only one command on one project at a time',
  +        'Instead of running the commands concurrently on the projects, run only one command on one project at a time',
           abbr: 's',
           defaultsTo: false);
     }
  
positive.code: //        .completeFeature();
  //  }
  //
  // ------- up to
  
  //  @u.SubCommand(help: 'Create a release of all the projects')
  
negative.code: 
    exec(String command, List<String> args,
        {String rootDirectory: '.',
          String projects,
          bool executeSerially: false}) async {
      final graph = await _loadGraph(rootDirectory);
  
      final processCommands = graph
          .multiProjectCommands(
          projectFilter: projectNameFilter(projects),
          defaultConcurrencyMode: executeSerially
              ? CommandConcurrencyMode.serialDepthFirst
              : CommandConcurrencyMode.concurrentProject)
          .processCommands;
  
      final result = await processCommands.execute(command, args);
      final output = result.map((r) => r.toReportString()).join('\n');
      stdout.write(output);
    }
  }
  
  class SetDependencies extends BaseJefeCommand {
    final name = "set-dependencies";
    final description = 'Set dependencies between projects';
  
    SetDependencies() {
      argParser.addOption('type',
          help: 'The type of dependency to set',
          allowed: const ['git', 'path', 'hosted']);
      addRootDirectory();
      addProjects();
    }
  
    Future run() {
      final type = argResults['type'];
      return setDependencies(type,
          rootDirectory: rootDirectory, projects: projects);
    }
  
    setDependencies(String type,
        {String rootDirectory: '.', String projects}) async {
      final graph = await _loadGraph(rootDirectory);
      final pubSpec = graph
          .multiProjectCommands(projectFilter: projectNameFilter(projects))
          .pubspecCommands;
  
      switch (type) {
        case 'git':
          return pubSpec.setToGitDependencies();
        case 'hosted':
          return pubSpec.setToHostedDependencies();
        case 'path':
        default:
          return pubSpec.setToPathDependencies();
      }
    }
  }
  
  class Test extends BaseJefeCommand {
    final name = "test";
    final description = 'Runs tests projects that have tests';
  
    Test() {
      addRootDirectory();
      addProjects();
    }
  
    Future run() {
      return test(rootDirectory: rootDirectory, projects: projects);
    }
  
    test({String rootDirectory: '.', String projects}) async {
      final graph = await _loadGraph(rootDirectory);
      final pub = graph
          .multiProjectCommands(projectFilter: projectNameFilter(projects))
          .pub;
  
      return pub.test();
    }
  }
  
  