Hello community, here is the log from the commit of package platformsh-cli for openSUSE:Factory checked in at 2018-02-13 10:32:08 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/platformsh-cli (Old) and /work/SRC/openSUSE:Factory/.platformsh-cli.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "platformsh-cli" Tue Feb 13 10:32:08 2018 rev:35 rq:575949 version:3.29.0 Changes: -------- --- /work/SRC/openSUSE:Factory/platformsh-cli/platformsh-cli.changes 2018-01-31 19:53:45.016291392 +0100 +++ /work/SRC/openSUSE:Factory/.platformsh-cli.new/platformsh-cli.changes 2018-02-13 10:32:20.082756333 +0100 @@ -1,0 +2,18 @@ +Mon Feb 12 21:57:54 UTC 2018 - ji...@boombatower.com + +- Update to version 3.29.0: + * Release v3.29.0 + * [db:dump] Remove --no-autocommit and simplify mysqldump args (#683) + * New lines in user:role to match user:add [skip changelog] + * Refactoring of user:add [skip changelog] + * Use getUsers() instead of getUser() in user:add [skip changelog] + * [user:add] [user:update] expand interactive help text + * Add `user:get` command (aliased to and deprecating `user:role`) + * [user:add] Improve `user:add` command to allow setting roles on all environments + * Expand redeploy warning to recommend "vset" + * Back to -dev + * [activity:get] Check for empty started_at when calculating duration + * [service:redis-cli] Recommend "redis info" command + * Merge CHANGELOG and manifest.json updates from master + +------------------------------------------------------------------- Old: ---- platformsh-cli-3.28.0.tar.xz New: ---- platformsh-cli-3.29.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ platformsh-cli.spec ++++++ --- /var/tmp/diff_new_pack.ZePFZ7/_old 2018-02-13 10:32:21.414708338 +0100 +++ /var/tmp/diff_new_pack.ZePFZ7/_new 2018-02-13 10:32:21.422708050 +0100 @@ -17,7 +17,7 @@ Name: platformsh-cli -Version: 3.28.0 +Version: 3.29.0 Release: 0 Summary: Tool for managing Platform.sh services from the command line # See licenses.txt for dependency licenses. ++++++ _service ++++++ --- /var/tmp/diff_new_pack.ZePFZ7/_old 2018-02-13 10:32:21.466706465 +0100 +++ /var/tmp/diff_new_pack.ZePFZ7/_new 2018-02-13 10:32:21.466706465 +0100 @@ -2,7 +2,7 @@ <service name="tar_scm" mode="disabled"> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> - <param name="revision">refs/tags/v3.28.0</param> + <param name="revision">refs/tags/v3.29.0</param> <param name="url">git://github.com/platformsh/platformsh-cli.git</param> <param name="scm">git</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.ZePFZ7/_old 2018-02-13 10:32:21.494705456 +0100 +++ /var/tmp/diff_new_pack.ZePFZ7/_new 2018-02-13 10:32:21.494705456 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">git://github.com/platformsh/platformsh-cli.git</param> - <param name="changesrevision">c6a6802cd9b738a9a3234fe32e4476c74ba98c6c</param> + <param name="changesrevision">55eff65515f99bd641aff9905c3b664f1119fc79</param> </service> </servicedata> ++++++ platformsh-cli-3.28.0.tar.xz -> platformsh-cli-3.29.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/CHANGELOG.md new/platformsh-cli-3.29.0/CHANGELOG.md --- old/platformsh-cli-3.28.0/CHANGELOG.md 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/CHANGELOG.md 2018-02-12 10:10:33.000000000 +0100 @@ -4,7 +4,17 @@ More readable, curated release notes can be found at: https://github.com/platformsh/platformsh-cli/releases -## [v3.28.0](https://github.com/platformsh/platformsh-cli/tree/v3.27.2) (2018-01-30) +## [v3.29.0](https://github.com/platformsh/platformsh-cli/tree/v3.29.0) (2018-02-12) +[Full Changelog](https://github.com/platformsh/platformsh-cli/compare/v3.28.0...v3.29.0) + +* [user:add] Improve `user:add` command to allow setting roles on all environments (aliased to `user:update`) +* [user:get] Add `user:get` command (aliased to and deprecating `user:role`) +* [db:dump] Remove --no-autocommit and simplify mysqldump args (#683) +* Expand redeploy warning to recommend `vset` +* [activity:get] Check for empty started_at when calculating duration +* [redis] Recommend "redis info" command + +## [v3.28.0](https://github.com/platformsh/platformsh-cli/tree/v3.28.0) (2018-01-30) [Full Changelog](https://github.com/platformsh/platformsh-cli/compare/v3.27.2...v3.28.0) * Improve `activity:log` output to show more activity information. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/README.md new/platformsh-cli-3.29.0/README.md --- old/platformsh-cli-3.28.0/README.md 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/README.md 2018-02-12 10:10:33.000000000 +0100 @@ -166,10 +166,10 @@ tunnel:list (tunnels) List SSH tunnels tunnel:open Open SSH tunnels to an app's relationships user - user:add Add a user to the project + user:add (user:update) Add a user to the project, or set their role(s) user:delete Delete a user from the project + user:get View a user's role(s) user:list (users) List project users - user:role View or change a user's role variable variable:delete Delete a variable from an environment variable:get (variables, vget) View variable(s) for an environment diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/config.yaml new/platformsh-cli-3.29.0/config.yaml --- old/platformsh-cli-3.28.0/config.yaml 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/config.yaml 2018-02-12 10:10:33.000000000 +0100 @@ -1,7 +1,7 @@ # Metadata about the CLI application itself. application: name: 'Platform.sh CLI' - version: '3.28.0' + version: '3.29.0' executable: 'platform' package_name: 'platformsh/cli' installer_url: 'https://platform.sh/cli/installer' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/dist/manifest.json new/platformsh-cli-3.29.0/dist/manifest.json --- old/platformsh-cli-3.28.0/dist/manifest.json 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/dist/manifest.json 2018-02-12 10:10:33.000000000 +0100 @@ -1,10 +1,10 @@ [ { "name": "platform.phar", - "sha1": "4ea45e3d18eaaba7422460ef03912f68638a7ccb", - "sha256": "fcf5e8d67c198621106a242937c7d6e35eb2df5044847c447b78f3aaa31bce8a", - "url": "https://github.com/platformsh/platformsh-cli/releases/download/v3.28.0/platform.phar", - "version": "3.28.0", + "sha1": "2f269ba903905599f2b2f6f94cde8174c551a25a", + "sha256": "7ca20c402d2514abb374fc4ec0deac04d2d1a0979e66336b3a4305806c414a38", + "url": "https://github.com/platformsh/platformsh-cli/releases/download/v3.29.0/platform.phar", + "version": "3.29.0", "php": { "min": "5.5.9" }, @@ -102,6 +102,11 @@ "notes": "* Improved `activity:log` output to show more activity information.\n* Added `activity:get` command, hidden for now.\n* Added `--date-fmt` option to `activity:list` and `snapshot:list`.\n* Added detection for the date.timezone ini setting, and the TZ environment variable.\n* Fixed inverted requirement of -e/-a options in activity:log (`-a` should make `-e` not required).\n* Fixed user-defined aliases being prefixed with \"@\" (thanks to @GROwen, #677).\n* Avoid fatal error if invalid YAML config is encountered during updateDrushAliases().\n* Fixed SSH commands for very old OpenSSH versions <5.9 (using -t instead of RequestTTY).\n* Updated dependencies (mainly Symfony 3.4.2 -> 3.4.4).", "show from": "3.27.0", "hide from": "3.28.0" + }, + { + "notes": "* [user:add] Improve `user:add` command to allow setting roles on all environments (aliased to `user:update`)\n* [user:get] Add `user:get` command (aliased to and deprecating `user:role`)\n* [db:dump] Remove --no-autocommit and simplify mysqldump args (#683)\n* Expand redeploy warning to recommend `vset`\n* [activity:get] Check for empty started_at when calculating duration\n* [redis] Recommend \"redis info\" command", + "show from": "3.28.0", + "hide from": "3.29.0" } ] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/Activity/ActivityGetCommand.php new/platformsh-cli-3.29.0/src/Command/Activity/ActivityGetCommand.php --- old/platformsh-cli-3.28.0/src/Command/Activity/ActivityGetCommand.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/Activity/ActivityGetCommand.php 2018-02-12 10:10:33.000000000 +0100 @@ -78,10 +78,10 @@ // Calculate the duration of the activity. if (!isset($properties['duration'])) { - $start = strtotime($activity->started_at); - $created = strtotime($activity->created_at); $end = strtotime($activity->isComplete() ? $activity->completed_at : $activity->updated_at); - $start = $start === $end ? $created : $start; + $created = strtotime($activity->created_at); + $start = !empty($activity->started_at) ? strtotime($activity->started_at) : 0; + $start = $start !== 0 && $start !== $end ? $start : $created; $properties['duration'] = $end - $start > 0 ? $end - $start : null; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/CommandBase.php new/platformsh-cli-3.29.0/src/Command/CommandBase.php --- old/platformsh-cli-3.28.0/src/Command/CommandBase.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/CommandBase.php 2018-02-12 10:10:33.000000000 +0100 @@ -555,9 +555,16 @@ protected function redeployWarning() { $this->stdErr->writeln([ - '<comment>The remote environment must be redeployed for the change to take effect.</comment>', - "Use 'git push' with new commit(s) to trigger a redeploy." + '', + '<comment>The remote environment(s) must be redeployed for the change to take effect.</comment>', + "Use 'git push' with new commit(s) to trigger a redeploy.", ]); + if (strpos($this->getName(), 'variable:') !== 0) { + $this->stdErr->writeln([ + 'Alternatively, add or change an environment variable, e.g.', + ' <comment>' . $this->config()->get('application.executable') . ' vset _redeploy "$(date)"</comment>' + ]); + } } /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/Db/DbDumpCommand.php new/platformsh-cli-3.29.0/src/Command/Db/DbDumpCommand.php --- old/platformsh-cli-3.28.0/src/Command/Db/DbDumpCommand.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/Db/DbDumpCommand.php 2018-02-12 10:10:33.000000000 +0100 @@ -142,7 +142,7 @@ break; default: - $dumpCommand = 'mysqldump --no-autocommit --single-transaction --opt --quote-names ' + $dumpCommand = 'mysqldump --single-transaction ' . $relationships->getSqlCommandArgs('mysqldump', $database); if ($schemaOnly) { $dumpCommand .= ' --no-data'; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/Service/RedisCliCommand.php new/platformsh-cli-3.29.0/src/Command/Service/RedisCliCommand.php --- old/platformsh-cli-3.28.0/src/Command/Service/RedisCliCommand.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/Service/RedisCliCommand.php 2018-02-12 10:10:33.000000000 +0100 @@ -25,7 +25,8 @@ ->addEnvironmentOption() ->addAppOption(); $this->addExample('Open the redis-cli shell'); - $this->addExample('Ping the redis server', 'ping'); + $this->addExample('Ping the Redis server', 'ping'); + $this->addExample('Show Redis status information', 'info'); $this->addExample('Scan keys', "-- --scan"); $this->addExample('Scan keys matching a pattern', '-- "--scan --pattern \'*-11*\'"'); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/User/UserAddCommand.php new/platformsh-cli-3.29.0/src/Command/User/UserAddCommand.php --- old/platformsh-cli-3.28.0/src/Command/User/UserAddCommand.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/User/UserAddCommand.php 2018-02-12 10:10:33.000000000 +0100 @@ -2,11 +2,14 @@ namespace Platformsh\Cli\Command\User; use Platformsh\Cli\Command\CommandBase; +use Platformsh\Client\Model\EnvironmentAccess; use Platformsh\Client\Model\ProjectAccess; -use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\Question; @@ -17,144 +20,272 @@ { $this ->setName('user:add') - ->setDescription('Add a user to the project') - ->addArgument('email', InputArgument::OPTIONAL, "The new user's email address") - ->addOption('role', null, InputOption::VALUE_REQUIRED, "The new user's role: 'admin' or 'viewer'"); + ->setAliases(['user:update']) + ->setDescription('Add a user to the project, or set their role(s)') + ->addArgument('email', InputArgument::OPTIONAL, "The user's email address") + ->addOption('role', 'r', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, "The user's role: 'admin' or 'viewer', or environment-specific role e.g. 'master:contributor' or 'stage:viewer'"); $this->addProjectOption(); $this->addNoWaitOption(); - $this->addExample('Add Alice as a new administrator', 'al...@example.com --role admin'); + $this->addExample('Add Alice as a project admin', 'al...@example.com -r admin'); + $this->addExample('Make Bob an admin on the "develop" and "stage" environments', 'b...@example.com -r develop:a,stage:a'); } protected function execute(InputInterface $input, OutputInterface $output) { $this->validateInput($input); + $project = $this->getSelectedProject(); /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */ $questionHelper = $this->getService('question_helper'); + // Process the --role option. + $roleInput = $input->getOption('role'); + if (count($input->getOption('role')) === 1) { + // Split comma-separated values. + $roleInput = preg_split('/[\s,]+/', reset($roleInput)); + } + $specifiedProjectRole = $this->getSpecifiedProjectRole($roleInput); + $specifiedEnvironmentRoles = $this->getSpecifiedEnvironmentRoles($roleInput); + unset($roleInput); + + // Process the [email] argument. $email = $input->getArgument('email'); - if ($email && !$this->validateEmail($email)) { - return 1; - } elseif (!$email) { - $question = new Question('Email address: '); - $question->setValidator([$this, 'validateEmail']); - $question->setMaxAttempts(5); - $email = $questionHelper->ask($input, $this->stdErr, $question); + if (!$email) { + $update = stripos($input->getFirstArgument(), ':u'); + if ($update && $input->isInteractive()) { + $choices = []; + foreach ($project->getUsers() as $access) { + $account = $this->api()->getAccount($access); + $choices[$account['email']] = $this->getUserLabel($access); + } + $email = $questionHelper->choose($choices, 'Enter a number to choose a user to update:'); + } else { + $question = new Question("Enter the user's email address: "); + $question->setValidator(function ($answer) { + return $this->validateEmail($answer); + }); + $question->setMaxAttempts(5); + $email = $questionHelper->ask($input, $this->stdErr, $question); + } + $this->stdErr->writeln(''); } + $this->validateEmail($email); - $project = $this->getSelectedProject(); + // Check the user's existing role on the project. + $existingProjectAccess = $this->api()->loadProjectAccessByEmail($project, $email); + $existingEnvironmentRoles = []; + if ($existingProjectAccess) { + // Exit if the user is the owner already. + if ($existingProjectAccess->id === $project->owner) { + $this->stdErr->writeln(sprintf('The user %s is the owner of %s.', $this->getUserLabel($existingProjectAccess), $this->api()->getProjectLabel($project))); + if ($specifiedProjectRole || $specifiedEnvironmentRoles) { + $this->stdErr->writeln(''); + $this->stdErr->writeln("<comment>The project owner's role(s) cannot be changed.</comment>"); - if ($this->api()->loadProjectAccessByEmail($project, $email)) { - $this->stdErr->writeln("The user already exists: <comment>$email</comment>"); - return 1; + return 1; + } + + return 0; + } + + // Check the user's existing role(s) on the project's environments. + $existingEnvironmentRoles = $this->getEnvironmentRoles($existingProjectAccess); } - $projectRole = $input->getOption('role'); - if ($projectRole && !in_array($projectRole, ProjectAccess::$roles)) { - $this->stdErr->writeln("Valid project-level roles are 'admin' or 'viewer'"); - return 1; - } elseif (!$projectRole) { - if (!$input->isInteractive()) { - $this->stdErr->writeln('You must specify a project role for the user.'); - return 1; + // If the user already exists, print a summary of their roles on the + // project and environments. + if ($existingProjectAccess) { + $this->stdErr->writeln(sprintf('Current role(s) of <info>%s</info> on %s:', $this->getUserLabel($existingProjectAccess), $this->api()->getProjectLabel($project))); + $this->stdErr->writeln(sprintf(' Project role: <info>%s</info>', $existingProjectAccess->role)); + foreach ($existingEnvironmentRoles as $id => $role) { + $this->stdErr->writeln(sprintf(' Role on <info>%s</info>: %s', $id, $role)); } - $this->stdErr->writeln("The user's project role can be 'viewer' ('v') or 'admin' ('a')."); - $question = new Question('Project role <question>[V/a]</question>: ', 'viewer'); - $question->setValidator([$this, 'validateRole']); - $question->setMaxAttempts(5); - $projectRole = $this->standardizeRole($questionHelper->ask($input, $this->stdErr, $question)); } - $environmentRoles = []; - $environments = []; - if ($projectRole !== 'admin') { - $environments = $this->api()->getEnvironments($project); - if ($input->isInteractive()) { - $this->stdErr->writeln( - "The user's environment-level roles can be 'viewer', 'contributor', 'admin', or 'none'." - ); - } - foreach ($environments as $environment) { - $question = new Question( - '<info>' . $environment->id . '</info> environment role <question>[v/c/a/N]</question>: ', - 'none' - ); - $question->setValidator([$this, 'validateRole']); - $question->setMaxAttempts(5); - $environmentRoles[$environment->id] = $this->standardizeRole( - $questionHelper->ask($input, $this->stdErr, $question) - ); + // Resolve or merge the project role. + $desiredProjectRole = $specifiedProjectRole ?: ($existingProjectAccess ? $existingProjectAccess->role : ProjectAccess::ROLE_VIEWER); + $provideProjectForm = !$input->getOption('role') && $input->isInteractive(); + if ($provideProjectForm) { + if ($existingProjectAccess) { + $this->stdErr->writeln(''); + } + $desiredProjectRole = $this->showProjectRoleForm($desiredProjectRole, $input); + } + + // Resolve or merge the environment role(s). + $provideEnvironmentForm = $input->isInteractive() + && $desiredProjectRole !== ProjectAccess::ROLE_ADMIN + && !$specifiedEnvironmentRoles; + $desiredEnvironmentRoles = []; + if ($desiredProjectRole !== ProjectAccess::ROLE_ADMIN) { + foreach ($this->api()->getEnvironments($project) as $id => $environment) { + if (isset($specifiedEnvironmentRoles[$id])) { + $desiredEnvironmentRoles[$id] = $specifiedEnvironmentRoles[$id]; + } elseif (isset($existingEnvironmentRoles[$id])) { + $desiredEnvironmentRoles[$id] = $existingEnvironmentRoles[$id]; + } + } + } + if ($provideEnvironmentForm) { + if ($existingProjectAccess || $provideProjectForm) { + $this->stdErr->writeln(''); } + $desiredEnvironmentRoles = $this->showEnvironmentRolesForm($desiredEnvironmentRoles, $input); } - $summaryFields = [ - 'Email address' => $email, - 'Project role' => $projectRole, - ]; - if (!empty($environmentRoles)) { - foreach ($environments as $environment) { - if (isset($environmentRoles[$environment->id])) { - $summaryFields[$environment->title] = $environmentRoles[$environment->id]; + // Build a list of the changes that are going to be made. + $changes = []; + if ($existingProjectAccess) { + if ($existingProjectAccess->role !== $desiredProjectRole) { + $changes[] = sprintf('Project role: <error>%s</error> -> <info>%s</info>', $existingProjectAccess->role, $desiredProjectRole); + } + } else { + $changes[] = sprintf('Project role: <info>%s</info>', $desiredProjectRole); + } + if ($desiredProjectRole !== ProjectAccess::ROLE_ADMIN) { + foreach ($this->api()->getEnvironments($project) as $id => $environment) { + $new = isset($desiredEnvironmentRoles[$id]) ? $desiredEnvironmentRoles[$id] : 'none'; + if ($existingEnvironmentRoles) { + $existing = isset($existingEnvironmentRoles[$id]) ? $existingEnvironmentRoles[$id] : 'none'; + if ($existing !== $new) { + $changes[] = sprintf('Role on <info>%s</info>: <error>%s</error> -> <info>%s</info>', $id, $existing, $new); + } + } elseif ($new !== 'none') { + $changes[] = sprintf('Role on <info>%s</info>: <info>%s</info>', $id, $new); } } } - $this->stdErr->writeln('Summary:'); - foreach ($summaryFields as $field => $value) { - $this->stdErr->writeln(" $field: <info>$value</info>"); + // Filter out environment roles of 'none' from the list. + $desiredEnvironmentRoles = array_filter($desiredEnvironmentRoles, function ($role) { + return $role !== 'none'; + }); + + // Require project non-admins to be added to at least one environment. + if ($desiredProjectRole === ProjectAccess::ROLE_VIEWER && !$desiredEnvironmentRoles) { + $this->stdErr->writeln(''); + $this->stdErr->writeln('<error>No environments selected.</error>'); + $this->stdErr->writeln('A non-admin user must be added to at least one environment.'); + + if ($existingProjectAccess) { + $this->stdErr->writeln(''); + $this->stdErr->writeln(sprintf( + 'To delete the user, run: <info>%s user:delete %s</info>', + $this->config()->get('application.executable'), + $this->api()->getAccount($existingProjectAccess)['email'] + )); + } + + return 1; } - $this->stdErr->writeln("<comment>Adding users can result in additional charges.</comment>"); + // Prevent changing environment access for project admins. + if ($desiredProjectRole === ProjectAccess::ROLE_ADMIN && $specifiedEnvironmentRoles) { + $this->stdErr->writeln(''); + $this->stdErr->writeln('<comment>A project admin has administrative access to all environments.</comment>'); + $this->stdErr->writeln("To set the user's environment role(s), set their project role to '" . ProjectAccess::ROLE_VIEWER . "'."); - if ($input->isInteractive()) { - if (!$questionHelper->confirm("Are you sure you want to add this user?")) { - return 1; + return 1; + } + + // Exit early if there are no changes to make. + if (empty($changes)) { + if ($provideProjectForm || $provideEnvironmentForm) { + $this->stdErr->writeln(''); + $this->stdErr->writeln('There are no changes to make.'); } + + return 0; } - $this->stdErr->writeln("Adding the user to the project"); - $result = $project->addUser($email, $projectRole); - $activities = $result->getActivities(); + // Add a new line if there has already been output. + if ($existingProjectAccess || $provideProjectForm || $provideEnvironmentForm) { + $this->stdErr->writeln(''); + } + + // Print a summary of the changes that are about to be made. + if ($existingProjectAccess) { + $this->stdErr->writeln('Summary of changes:'); + } else { + $this->stdErr->writeln(sprintf('Adding the user <info>%s</info> to %s:', $email, $this->api()->getProjectLabel($project))); + } + foreach ($changes as $change) { + $this->stdErr->writeln(' ' . $change); + } + $this->stdErr->writeln(''); - $this->stdErr->writeln("User <info>$email</info> created"); + // Ask for confirmation. + if ($existingProjectAccess) { + if (!$questionHelper->confirm('Are you sure you want to make these change(s)?')) { - $success = true; - if (!empty($environmentRoles)) { + return 1; + } + } else { + $this->stdErr->writeln('<comment>Adding users can result in additional charges.</comment>'); + $this->stdErr->writeln(''); + if (!$questionHelper->confirm('Are you sure you want to add this user?')) { + + return 1; + } + } + + // Make the required modifications on the project level: add the user, + // change their role, or do nothing. + if (!$existingProjectAccess) { + $this->stdErr->writeln("Adding the user to the project"); + $result = $project->addUser($email, $desiredProjectRole); + $activities = $result->getActivities(); /** @var ProjectAccess $projectAccess */ $projectAccess = $result->getEntity(); $uuid = $projectAccess->id; - - $this->stdErr->writeln("Setting environment role(s)"); - foreach ($environmentRoles as $environmentId => $role) { - if (!isset($environments[$environmentId])) { - $this->stdErr->writeln("<error>Environment not found: $environmentId</error>"); - $success = false; - continue; - } - if ($role == 'none') { - continue; - } - $access = $environments[$environmentId]->getUser($uuid); - if ($access) { - $this->stdErr->writeln("Modifying the user's role on the environment: <info>$environmentId</info>"); - $result = $access->update(['role' => $role]); + } elseif ($existingProjectAccess->role !== $desiredProjectRole) { + $this->stdErr->writeln("Setting the user's project role to: $desiredProjectRole"); + $result = $existingProjectAccess->update(['role' => $desiredProjectRole]); + $activities = $result->getActivities(); + $uuid = $existingProjectAccess->id; + } else { + $uuid = $existingProjectAccess->id; + $activities = []; + } + + // Make the desired changes at the environment level. + if ($desiredProjectRole !== ProjectAccess::ROLE_ADMIN) { + foreach ($this->api()->getEnvironments($project) as $environmentId => $environment) { + $role = isset($desiredEnvironmentRoles[$environmentId]) ? $desiredEnvironmentRoles[$environmentId] : 'none'; + $access = $environment->getUser($uuid); + if ($role === 'none') { + if ($access) { + $this->stdErr->writeln("Removing the user from the environment <info>$environmentId</info>"); + $result = $access->delete(); + } else { + continue; + } } else { - $this->stdErr->writeln("Adding the user to the environment: <info>$environmentId</info>"); - $result = $environments[$environmentId]->addUser($uuid, $role); + if ($access) { + if ($access->role === $role) { + continue; + } + $this->stdErr->writeln("Setting the user's role on the environment <info>$environmentId</info> to: $role"); + $result = $access->update(['role' => $role]); + } else { + $this->stdErr->writeln("Adding the user to the environment: <info>$environmentId</info>"); + $result = $environment->addUser($uuid, $role); + } } $activities = array_merge($activities, $result->getActivities()); } } + // Wait for activities to complete. if (!$input->getOption('no-wait')) { /** @var \Platformsh\Cli\Service\ActivityMonitor $activityMonitor */ $activityMonitor = $this->getService('activity_monitor'); if (!$activityMonitor->waitMultiple($activities, $project)) { - $success = false; + return 1; } } - return $success ? 0 : 1; + return 0; } /** @@ -162,48 +293,254 @@ * * @return string */ - public function validateRole($value) + private function validateProjectRole($value) { - if (empty($value) - || !in_array(strtolower($value), ['admin', 'contributor', 'viewer', 'none', 'a', 'c', 'v', 'n'])) { - throw new RuntimeException("Invalid role: $value"); - } + return $this->matchRole($value, ProjectAccess::$roles); + } - return $value; + /** + * @param string $value + * + * @return string + */ + private function validateEnvironmentRole($value) + { + return $this->matchRole($value, array_merge(EnvironmentAccess::$roles, ['none'])); } /** + * Validate an email address. + * * @param string $value * + * @throws \Symfony\Component\Console\Exception\InvalidArgumentException + * * @return string */ - public function validateEmail($value) + private function validateEmail($value) { - if (empty($value) || !filter_var($value, FILTER_VALIDATE_EMAIL)) { - throw new RuntimeException("Invalid email address: $value"); + if (empty($value)) { + throw new InvalidArgumentException('An email address is required.'); + } + if (!$filtered = filter_var($value, FILTER_VALIDATE_EMAIL)) { + throw new InvalidArgumentException('Invalid email address: ' . $value); } - return $value; + return $filtered; } /** - * @param string $givenRole + * Complete a role name based on an array of allowed roles. + * + * @param string $input + * @param string[] $roles * * @return string - * @throws \Exception */ - protected function standardizeRole($givenRole) + private function matchRole($input, array $roles) { - $possibleRoles = ['viewer', 'admin', 'contributor', 'none']; - if (in_array($givenRole, $possibleRoles)) { - return $givenRole; + foreach ($roles as $role) { + if (strpos($role, strtolower($input)) === 0) { + return $role; + } } - $role = strtolower($givenRole); - foreach ($possibleRoles as $possibleRole) { - if (strpos($possibleRole, $role) === 0) { - return $possibleRole; + + throw new InvalidArgumentException('Invalid role: ' . $input); + } + + /** + * Expand roles into a list with abbreviations. + * + * @param string[] $roles + * + * @return string + */ + private function describeRoles(array $roles) + { + $withInitials = array_map(function ($role) { + return sprintf('%s (%s)', $role, substr($role, 0, 1)); + }, $roles); + $last = array_pop($withInitials); + + return implode(' or ', [implode(', ', $withInitials), $last]); + } + + /** + * Describe the input for a roles question, e.g. [a/c/v/n]. + * + * @param string[] $roles + * + * @return string + */ + private function describeRoleInput(array $roles) + { + return '[' . implode('/', array_map(function ($role) { + return substr($role, 0, 1); + }, $roles)) . ']'; + } + + /** + * Return a label describing a user. + * + * @param \Platformsh\Client\Model\ProjectAccess $access + * + * @return string + */ + private function getUserLabel(ProjectAccess $access) + { + $account = $this->api()->getAccount($access); + + return sprintf('<info>%s</info> (%s)', $account['display_name'], $account['email']); + } + + /** + * Show the form for entering the project role. + * + * @param string $defaultRole + * @param \Symfony\Component\Console\Input\InputInterface $input + * + * @return string + */ + private function showProjectRoleForm($defaultRole, InputInterface $input) + { + /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */ + $questionHelper = $this->getService('question_helper'); + + $this->stdErr->writeln("The user's project role can be " . $this->describeRoles(ProjectAccess::$roles) . '.'); + $this->stdErr->writeln(''); + $question = new Question( + sprintf('Project role (default: %s) <question>%s</question>: ', $defaultRole, $this->describeRoleInput(ProjectAccess::$roles)), + $defaultRole + ); + $question->setValidator(function ($answer) { + return $this->validateProjectRole($answer); + }); + $question->setMaxAttempts(5); + $question->setAutocompleterValues(ProjectAccess::$roles); + + return $questionHelper->ask($input, $this->stdErr, $question); + } + + /** + * Load the user's roles on the project's environments. + * + * @param \Platformsh\Client\Model\ProjectAccess $projectAccess + * + * @return array + */ + private function getEnvironmentRoles(ProjectAccess $projectAccess) + { + $environmentRoles = []; + if ($projectAccess->role === ProjectAccess::ROLE_ADMIN) { + return []; + } + + // @todo find out why $environment->getUser() has permission issues - it would be a lot faster than this + + $progress = new ProgressBar(isset($this->stdErr) && $this->stdErr->isDecorated() ? $this->stdErr : new NullOutput()); + $progress->setMessage('Loading environments...'); + $progress->setFormat('%message% %current%/%max%'); + $environments = $this->api()->getEnvironments($this->getSelectedProject()); + $progress->start(count($environments)); + foreach ($environments as $environment) { + foreach ($environment->getUsers() as $access) { + if ($access->user === $projectAccess->id) { + $environmentRoles[$environment->id] = $access->role; + } + } + $progress->advance(); + } + $progress->finish(); + $progress->clear(); + + return $environmentRoles; + } + + /** + * Show the form for entering environment roles. + * + * @param array $defaultEnvironmentRoles + * @param \Symfony\Component\Console\Input\InputInterface $input + * + * @return array + * The environment roles (keyed by environment ID) including the user's + * answers. + */ + private function showEnvironmentRolesForm(array $defaultEnvironmentRoles, InputInterface $input) + { + /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */ + $questionHelper = $this->getService('question_helper'); + $desiredEnvironmentRoles = []; + $validEnvironmentRoles = array_merge(EnvironmentAccess::$roles, ['none']); + $this->stdErr->writeln("The user's environment role(s) can be " . $this->describeRoles($validEnvironmentRoles) . '.'); + $initials = $this->describeRoleInput($validEnvironmentRoles); + $this->stdErr->writeln(''); + foreach (array_keys($this->api()->getEnvironments($this->getSelectedProject())) as $id) { + $default = isset($defaultEnvironmentRoles[$id]) ? $defaultEnvironmentRoles[$id] : 'none'; + $question = new Question( + sprintf('Role on <info>%s</info> (default: %s) <question>%s</question>: ', $id, $default, $initials), + $default + ); + $question->setValidator(function ($answer) { + if ($answer === 'q' || $answer === 'quit') { + return $answer; + } + + return $this->validateEnvironmentRole($answer); + }); + $question->setAutocompleterValues(array_merge($validEnvironmentRoles, ['quit'])); + $question->setMaxAttempts(5); + $answer = $questionHelper->ask($input, $this->stdErr, $question); + if ($answer === 'q' || $answer === 'quit') { + break; + } else { + $desiredEnvironmentRoles[$id] = $answer; } } - throw new RuntimeException("Role not found: $givenRole"); + + return $desiredEnvironmentRoles; + } + + /** + * Extract the specified project role from the list (given in --role). + * + * @param array $roles + * + * @return string|null + * The project role, or null if none is specified. + */ + private function getSpecifiedProjectRole(array $roles) + { + foreach ($roles as $role) { + if (strpos($role, ':') === false) { + return $this->validateProjectRole($role); + } + } + + return null; + } + + /** + * Extract the specified environment roles from the list (given in --role). + * + * @param string[] $roles + * + * @return array + * An array of environment roles, keyed by environment ID. + */ + private function getSpecifiedEnvironmentRoles(array $roles) + { + $environmentRoles = []; + foreach ($roles as $role) { + if (strpos($role, ':') !== false) { + list($id, $role) = explode(':', $role, 2); + if (!$this->api()->getEnvironment($id, $this->getSelectedProject())) { + throw new InvalidArgumentException('Environment not found: ' . $id); + } + $environmentRoles[$id] = $this->validateEnvironmentRole($role); + } + } + + return $environmentRoles; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/User/UserListCommand.php new/platformsh-cli-3.29.0/src/Command/User/UserListCommand.php --- old/platformsh-cli-3.28.0/src/Command/User/UserListCommand.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/User/UserListCommand.php 2018-02-12 10:10:33.000000000 +0100 @@ -45,6 +45,14 @@ ksort($rows); $table->render(array_values($rows), ['Email address', 'Name', 'Project role', 'ID']); + + if (!$table->formatIsMachineReadable()) { + $this->stdErr->writeln(''); + $executable = $this->config()->get('application.executable'); + $this->stdErr->writeln("To view a user's role(s), run: <info>$executable user:get [email]</info>"); + $this->stdErr->writeln("To change a user's role(s), run: <info>$executable user:add [email]</info>"); + } + return 0; } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Command/User/UserRoleCommand.php new/platformsh-cli-3.29.0/src/Command/User/UserRoleCommand.php --- old/platformsh-cli-3.28.0/src/Command/User/UserRoleCommand.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Command/User/UserRoleCommand.php 2018-02-12 10:10:33.000000000 +0100 @@ -12,25 +12,24 @@ class UserRoleCommand extends CommandBase { - protected function configure() { $this - ->setName('user:role') - ->setDescription("View or change a user's role") - ->addArgument('email', InputArgument::REQUIRED, "The user's email address") - ->addOption('role', 'r', InputOption::VALUE_REQUIRED, "A new role for the user") + ->setName('user:get') + ->setDescription("View a user's role(s)") + ->addArgument('email', InputArgument::OPTIONAL, "The user's email address") ->addOption('level', 'l', InputOption::VALUE_REQUIRED, "The role level ('project' or 'environment')") - ->addOption('pipe', null, InputOption::VALUE_NONE, 'Output the role only'); + ->addOption('pipe', null, InputOption::VALUE_NONE, 'Output the role to stdout (after making any changes)'); $this->addProjectOption() ->addEnvironmentOption() ->addNoWaitOption(); + + // Backwards compatibility. + $this->setHiddenAliases(['user:role']); + $this->addOption('role', 'r', InputOption::VALUE_REQUIRED, "[Deprecated: use user:update to change a user's role(s)]"); + $this->addExample("View Alice's role on the project", 'al...@example.com'); $this->addExample("View Alice's role on the environment", 'al...@example.com --level environment'); - $this->addExample( - "Give Alice the 'contributor' role on the environment 'test'", - 'al...@example.com --level environment --environment test --role contributor' - ); } protected function execute(InputInterface $input, OutputInterface $output) @@ -46,15 +45,37 @@ $this->validateInput($input, $level !== 'environment'); $project = $this->getSelectedProject(); + $this->warnAboutDeprecatedOptions(['role']); + + /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */ + $questionHelper = $this->getService('question_helper'); + + // Load the user. + $email = $input->getArgument('email'); + if ($email === null && $input->isInteractive()) { + $choices = []; + foreach ($project->getUsers() as $access) { + $account = $this->api()->getAccount($access); + $choices[$account['email']] = sprintf('%s (%s)', $account['display_name'], $account['email']); + } + $email = $questionHelper->choose($choices, 'Enter a number to choose a user:'); + $this->stdErr->writeln(''); + } + $projectAccess = $this->api()->loadProjectAccessByEmail($project, $email); + if (!$projectAccess) { + $this->stdErr->writeln("User not found: <error>$email</error>"); + + return 1; + } + if ($level === null && $role && $this->hasSelectedEnvironment() && $input->isInteractive()) { $environment = $this->getSelectedEnvironment(); - /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */ - $questionHelper = $this->getService('question_helper'); - $question = new ChoiceQuestion('For which access level do you want to set the role?', [ + $question = new ChoiceQuestion('What role level do you want to set to "' . $role . '"?', [ 'project' => 'The project', 'environment' => sprintf('The environment (%s)', $environment->id), ]); $level = $questionHelper->ask($input, $output, $question); + $this->stdErr->writeln(''); } elseif ($level === null && $role) { $level = 'project'; } @@ -69,100 +90,35 @@ return 1; } - // Load the user. - $email = $input->getArgument('email'); - $projectAccess = $this->api()->loadProjectAccessByEmail($project, $email); - if (!$projectAccess) { - $this->stdErr->writeln("User not found: <error>$email</error>"); - - return 1; - } - - // Get the current role. - if ($level !== 'environment') { - $currentRole = $projectAccess->role; - $environmentAccess = false; - } else { - $environmentAccess = $this->getSelectedEnvironment()->getUser($projectAccess->id); - $currentRole = $environmentAccess === false ? 'none' : $environmentAccess->role; - } - - if ($role === $currentRole) { - $this->stdErr->writeln("There is nothing to change"); - } elseif ($role && $project->owner === $projectAccess->id) { - $this->stdErr->writeln(sprintf( - 'The user <error>%s</error> is the owner of the project %s.', - $email, - $this->api()->getProjectLabel($project, 'error') - )); - $this->stdErr->writeln("You cannot change the role of the project's owner."); - return 1; - } elseif ($role && $level === 'environment' && $projectAccess->role === ProjectAccess::ROLE_ADMIN) { - $this->stdErr->writeln(sprintf( - 'The user <error>%s</error> is an admin on the project %s.', - $email, - $this->api()->getProjectLabel($project, 'error') - )); - $this->stdErr->writeln('You cannot change the environment-level role of a project admin.'); - return 1; - } elseif ($role && $level !== 'environment') { - $result = $projectAccess->update(['role' => $role]); - $this->stdErr->writeln("User <info>$email</info> updated"); - } elseif ($role && $level === 'environment') { - $environment = $this->getSelectedEnvironment(); - if ($role === 'none') { - if ($environmentAccess instanceof EnvironmentAccess) { - $result = $environmentAccess->delete(); - } - } elseif ($environmentAccess instanceof EnvironmentAccess) { - $result = $environmentAccess->update(['role' => $role]); - } else { - $result = $environment->addUser($projectAccess->id, $role); + $args = [ + 'email' => $email, + '--role' => [], + '--project' => $project->id, + ]; + if ($role) { + if ($level === 'project') { + $args['--role'][] = $role; + } elseif ($level === 'environment') { + $args['--role'][] = $this->getSelectedEnvironment()->id . ':' . $role; } - $this->stdErr->writeln("User <info>$email</info> updated"); + } else { + $args['--yes'] = true; } - - if (isset($result) && !$input->getOption('no-wait')) { - /** @var \Platformsh\Cli\Service\ActivityMonitor $activityMonitor */ - $activityMonitor = $this->getService('activity_monitor'); - $activityMonitor->waitMultiple($result->getActivities(), $project); + $result = $this->runOtherCommand($role ? 'user:update' : 'user:add', $args, $output); + if ($result !== 0) { + return $result; } if ($input->getOption('pipe')) { + $uuid = $projectAccess->id; if ($level !== 'environment') { - $output->writeln($projectAccess->role); + $projectAccess = $this->api()->loadProjectAccessByEmail($project, $email); + $currentRole = $projectAccess ? $projectAccess->role : 'none'; } else { - $access = $this->getSelectedEnvironment()->getUser($projectAccess->id); - $output->writeln($access ? $access->role : 'none'); - } - - return 0; - } - - if ($level !== 'environment') { - $output->writeln("Project role: <info>{$projectAccess->role}</info>"); - } - - $environments = []; - if ($level === 'environment') { - $environments = [$this->getSelectedEnvironment()]; - } elseif ($level === null && $projectAccess->role !== ProjectAccess::ROLE_ADMIN) { - $environments = $this->api()->getEnvironments($project); - $this->api()->sortResources($environments, 'id'); - if ($this->hasSelectedEnvironment()) { - $environment = $this->getSelectedEnvironment(); - unset($environments[$environment->id]); - array_splice($environments, 0, 0, [$environment->id => $environment]); + $environmentAccess = $this->getSelectedEnvironment()->getUser($uuid); + $currentRole = $environmentAccess ? $environmentAccess->role : 'none'; } - } - - foreach ($environments as $environment) { - $access = $environment->getUser($projectAccess->id); - $output->writeln(sprintf( - 'Role for environment %s: <info>%s</info>', - $environment->id, - $access ? $access->role : 'none' - )); + $output->writeln($currentRole); } return 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Service/Api.php new/platformsh-cli-3.29.0/src/Service/Api.php --- old/platformsh-cli-3.28.0/src/Service/Api.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Service/Api.php 2018-02-12 10:10:33.000000000 +0100 @@ -52,6 +52,9 @@ /** @var bool */ protected static $environmentsCacheRefreshed = false; + /** @var \Platformsh\Client\Model\Account[] */ + protected static $accountsCache = []; + /** @var array */ protected static $notFound = []; @@ -426,10 +429,15 @@ */ public function getAccount(ProjectAccess $user, $reset = false) { + if (isset(self::$accountsCache[$user->id]) && !$reset) { + return self::$accountsCache[$user->id]; + } + $cacheKey = 'account:' . $user->id; if ($reset || !($details = $this->cache->fetch($cacheKey))) { $details = $user->getAccount()->getProperties(); $this->cache->save($cacheKey, $details, $this->config->get('api.users_ttl')); + self::$accountsCache[$user->id] = $details; } return $details; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/platformsh-cli-3.28.0/src/Service/PropertyFormatter.php new/platformsh-cli-3.29.0/src/Service/PropertyFormatter.php --- old/platformsh-cli-3.28.0/src/Service/PropertyFormatter.php 2018-01-30 17:56:41.000000000 +0100 +++ new/platformsh-cli-3.29.0/src/Service/PropertyFormatter.php 2018-02-12 10:10:33.000000000 +0100 @@ -42,7 +42,8 @@ case 'started_at': case 'completed_at': case 'ssl.expires_on': - return $this->formatDate($value); + $value = $this->formatDate($value); + break; case 'ssl': if ($property === 'ssl' && is_array($value) && isset($value['expires_on'])) { @@ -76,7 +77,7 @@ /** * @param string $value * - * @return string + * @return string|null */ protected function formatDate($value) { @@ -94,7 +95,7 @@ $timestamp = is_numeric($value) ? $value : strtotime($value); - return date($format, $timestamp); + return $timestamp === false ? null : date($format, $timestamp); } /** ++++++ platformsh-cli-vendor.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/autoload.php new/vendor/autoload.php --- old/vendor/autoload.php 2018-01-31 04:51:30.626379513 +0100 +++ new/vendor/autoload.php 2018-02-12 22:57:57.119722174 +0100 @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit356ede5f5e6cb0e287cfa8ee0def1ebe::getLoader(); +return ComposerAutoloaderInit1000482ab31b6ea30c0fe42bed510766::getLoader(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/composer/autoload_real.php new/vendor/composer/autoload_real.php --- old/vendor/composer/autoload_real.php 2018-01-31 04:51:30.626379513 +0100 +++ new/vendor/composer/autoload_real.php 2018-02-12 22:57:57.119722174 +0100 @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit356ede5f5e6cb0e287cfa8ee0def1ebe +class ComposerAutoloaderInit1000482ab31b6ea30c0fe42bed510766 { private static $loader; @@ -19,15 +19,15 @@ return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit356ede5f5e6cb0e287cfa8ee0def1ebe', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit1000482ab31b6ea30c0fe42bed510766', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit356ede5f5e6cb0e287cfa8ee0def1ebe', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit1000482ab31b6ea30c0fe42bed510766', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit356ede5f5e6cb0e287cfa8ee0def1ebe::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit1000482ab31b6ea30c0fe42bed510766::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -48,19 +48,19 @@ $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit356ede5f5e6cb0e287cfa8ee0def1ebe::$files; + $includeFiles = Composer\Autoload\ComposerStaticInit1000482ab31b6ea30c0fe42bed510766::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire356ede5f5e6cb0e287cfa8ee0def1ebe($fileIdentifier, $file); + composerRequire1000482ab31b6ea30c0fe42bed510766($fileIdentifier, $file); } return $loader; } } -function composerRequire356ede5f5e6cb0e287cfa8ee0def1ebe($fileIdentifier, $file) +function composerRequire1000482ab31b6ea30c0fe42bed510766($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/composer/autoload_static.php new/vendor/composer/autoload_static.php --- old/vendor/composer/autoload_static.php 2018-01-31 04:51:30.626379513 +0100 +++ new/vendor/composer/autoload_static.php 2018-02-12 22:57:57.119722174 +0100 @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit356ede5f5e6cb0e287cfa8ee0def1ebe +class ComposerStaticInit1000482ab31b6ea30c0fe42bed510766 { public static $files = array ( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', @@ -189,9 +189,9 @@ public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit356ede5f5e6cb0e287cfa8ee0def1ebe::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit356ede5f5e6cb0e287cfa8ee0def1ebe::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit356ede5f5e6cb0e287cfa8ee0def1ebe::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit1000482ab31b6ea30c0fe42bed510766::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit1000482ab31b6ea30c0fe42bed510766::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit1000482ab31b6ea30c0fe42bed510766::$classMap; }, null, ClassLoader::class); }