#!/usr/bin/env php setTagline('set members'); $args->setSynopsis(<<parseStandardArguments(); $args->parse( array( array( 'name' => 'dry-run', 'help' => pht('Only show what changes would be made.'), ), )); $viewer = PhabricatorUser::getOmnipotentUser(); // manually maintained config $conf = array( 'Zelda' => 'Zelda-Sprint' ); echo "Run at ".date(DateTime::ISO8601)."...\n"; foreach($conf as $master_project_name => $clone_prefix) { $slug = trim($master_project_name, '#'); $project = id(new PhabricatorProjectQuery()) ->setViewer($viewer) ->withSlugs(array($slug)) ->needMembers(true) ->executeOne(); if (!$project) { throw new Exception(pht('No project "%s" exists!', $slug)); } echo "Processing master project: ".$project->getName()."\n"; $current_master_phids = $project->getMemberPHIDs(); $current_master_users = array(); if (!$current_master_users) { $current_master_users = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withPHIDs($current_master_phids) ->execute(); } // We need all projects since there is no way to search by prefix $all_projects = id(new PhabricatorProjectQuery()) ->setViewer($viewer) ->needMembers(true) ->withStatus(PhabricatorProjectQuery::STATUS_ACTIVE) ->execute(); $clone_projects = array(); foreach ($all_projects as $canidate_project) { if (startsWith($canidate_project->getName(), $clone_prefix)) { echo "Clone Project: ".$canidate_project->getName()."\n"; cloneProjectMembers($viewer, mpull($current_master_users, null, 'getPHID'), $canidate_project, $args->getArg('dry-run')); } } } echo "Done.\n"; // http://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php function startsWith($haystack, $needle) { return $needle === "" || strpos($haystack, $needle) === 0; } function cloneProjectMembers($viewer, $current_master_users, $clone_project, $dry_run) { $current_clone_phids = $clone_project->getMemberPHIDs(); $current_clone_users = array(); if (!empty($current_clone_phids)) { $current_clone_users = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withPHIDs($current_clone_phids) ->execute(); } $all_users = mpull($current_master_users, null, 'getPHID') + mpull($current_clone_users, null, 'getPHID'); $add = array_diff_key($current_master_users, array_fuse($current_clone_phids)); $rem = array_diff_key(array_fuse($current_clone_phids), $current_master_users); $add_users = array_select_keys($all_users, array_keys($add)); $rem_users = array_select_keys($all_users, array_keys($rem)); if (!$add) { echo "No users will be added.\n\n"; } else { echo "These users will be added:\n"; foreach ($add_users as $user) { echo " ".$user->getUsername()."\n"; } echo "\n"; } if (!$rem) { echo "No users will be removed.\n\n"; } else { echo "These users will be removed:\n"; foreach ($rem as $rem_phid => $ignored) { $name = $rem_phid; if (isset($rem_users[$rem_phid])) { $name = $rem_users[$rem_phid]->getUsername(); } echo " ".$name."\n"; } echo "\n"; } if ($dry_run) { echo "End of dry run.\n"; exit(0); } if (!$add && !$rem) { echo "No changes to apply.\n"; exit(0); } echo "Applying changes...\n"; $type_member = PhabricatorEdgeConfig::TYPE_PROJ_MEMBER; $editor = id(new PhabricatorEdgeEditor()); foreach ($add as $phid => $ignored) { $editor->addEdge($clone_project->getPHID(), $type_member, $phid); } foreach ($rem as $phid => $ignored) { $editor->removeEdge($clone_project->getPHID(), $type_member, $phid); } $editor->save(); }