Hello community,

here is the log from the commit of package platformsh-cli for openSUSE:Factory 
checked in at 2017-11-30 12:45:29
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/platformsh-cli (Old)
 and      /work/SRC/openSUSE:Factory/.platformsh-cli.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "platformsh-cli"

Thu Nov 30 12:45:29 2017 rev:25 rq:546338 version:3.23.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/platformsh-cli/platformsh-cli.changes    
2017-11-17 11:00:56.714655402 +0100
+++ /work/SRC/openSUSE:Factory/.platformsh-cli.new/platformsh-cli.changes       
2017-11-30 12:45:32.137604158 +0100
@@ -1,0 +2,12 @@
+Wed Nov 29 03:34:04 UTC 2017 - [email protected]
+
+- Update to version 3.23.0:
+  * Release v3.23.0
+  * mount commands: add --exclude and --include (#651)
+  * Allow projects to be identified from their public website URL (#649)
+  * Add excluded_environments option for webhooks (#652)
+  * Add GitLab integration support (#647)
+  * Improve mount commands output
+  * Support new mount style
+
+-------------------------------------------------------------------

Old:
----
  platformsh-cli-3.22.3.tar.xz

New:
----
  platformsh-cli-3.23.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ platformsh-cli.spec ++++++
--- /var/tmp/diff_new_pack.yCeASk/_old  2017-11-30 12:45:33.189565916 +0100
+++ /var/tmp/diff_new_pack.yCeASk/_new  2017-11-30 12:45:33.193565770 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           platformsh-cli
-Version:        3.22.3
+Version:        3.23.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.yCeASk/_old  2017-11-30 12:45:33.233564316 +0100
+++ /var/tmp/diff_new_pack.yCeASk/_new  2017-11-30 12:45:33.233564316 +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.22.3</param>
+    <param name="revision">refs/tags/v3.23.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.yCeASk/_old  2017-11-30 12:45:33.257563444 +0100
+++ /var/tmp/diff_new_pack.yCeASk/_new  2017-11-30 12:45:33.261563298 +0100
@@ -1,6 +1,6 @@
 <servicedata>
   <service name="tar_scm">
     <param name="url">git://github.com/platformsh/platformsh-cli.git</param>
-    <param 
name="changesrevision">da1c7f22409c1b63dd2dd23d99542774506b41c7</param>
+    <param 
name="changesrevision">2eed15b1fd4791dd1b4e4050b648b6823c06dfc4</param>
   </service>
 </servicedata>

++++++ licenses.txt ++++++
--- /var/tmp/diff_new_pack.yCeASk/_old  2017-11-30 12:45:33.317561263 +0100
+++ /var/tmp/diff_new_pack.yCeASk/_new  2017-11-30 12:45:33.317561263 +0100
@@ -15,7 +15,7 @@
 guzzlehttp/streams                  3.0.0    MIT           
 padraic/humbug_get_contents         1.0.4    BSD-3-Clause  
 padraic/phar-updater                1.0.4    BSD-3-Clause  
-platformsh/client                   v0.12.0  MIT           
+platformsh/client                   v0.12.1  MIT           
 platformsh/console-form             v0.0.13  MIT           
 psr/container                       1.0.0    MIT           
 psr/log                             1.0.2    MIT           

++++++ platformsh-cli-3.22.3.tar.xz -> platformsh-cli-3.23.0.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/composer.lock 
new/platformsh-cli-3.23.0/composer.lock
--- old/platformsh-cli-3.22.3/composer.lock     2017-11-16 11:12:57.000000000 
+0100
+++ new/platformsh-cli-3.23.0/composer.lock     2017-11-24 17:31:28.000000000 
+0100
@@ -594,16 +594,16 @@
         },
         {
             "name": "platformsh/client",
-            "version": "v0.12.0",
+            "version": "v0.12.1",
             "source": {
                 "type": "git",
                 "url": 
"https://github.com/platformsh/platformsh-client-php.git";,
-                "reference": "e5ce468ddc35d8a95fff79579a17b076cd5831c4"
+                "reference": "945ba687f110c3c74e8c250b1b4afd2d03062c7c"
             },
             "dist": {
                 "type": "zip",
-                "url": 
"https://api.github.com/repos/platformsh/platformsh-client-php/zipball/e5ce468ddc35d8a95fff79579a17b076cd5831c4";,
-                "reference": "e5ce468ddc35d8a95fff79579a17b076cd5831c4",
+                "url": 
"https://api.github.com/repos/platformsh/platformsh-client-php/zipball/945ba687f110c3c74e8c250b1b4afd2d03062c7c";,
+                "reference": "945ba687f110c3c74e8c250b1b4afd2d03062c7c",
                 "shasum": ""
             },
             "require": {
@@ -639,7 +639,7 @@
                 }
             ],
             "description": "Platform.sh API client",
-            "time": "2017-09-20T08:28:37+00:00"
+            "time": "2017-11-16T12:15:47+00:00"
         },
         {
             "name": "platformsh/console-form",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/config.yaml 
new/platformsh-cli-3.23.0/config.yaml
--- old/platformsh-cli-3.22.3/config.yaml       2017-11-16 11:12:57.000000000 
+0100
+++ new/platformsh-cli-3.23.0/config.yaml       2017-11-24 17:31:28.000000000 
+0100
@@ -1,7 +1,7 @@
 # Metadata about the CLI application itself.
 application:
   name: 'Platform.sh CLI'
-  version: '3.22.3'
+  version: '3.23.0'
   executable: 'platform'
   package_name: 'platformsh/cli'
   installer_url: 'https://platform.sh/cli/installer'
@@ -33,6 +33,7 @@
 service:
   name: 'Platform.sh'
   env_prefix: 'PLATFORM_'
+  header_prefix: 'X-Platform'
   app_config_file: '.platform.app.yaml'
   project_config_dir: '.platform'
   docs_url: 'https://docs.platform.sh'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/services.yaml 
new/platformsh-cli-3.23.0/services.yaml
--- old/platformsh-cli-3.22.3/services.yaml     2017-11-16 11:12:57.000000000 
+0100
+++ new/platformsh-cli-3.23.0/services.yaml     2017-11-24 17:31:28.000000000 
+0100
@@ -22,6 +22,9 @@
     git:
         class:     '\Platformsh\Cli\Service\Git'
         arguments: ['@shell']
+    identifier:
+        class:     '\Platformsh\Cli\Service\Identifier'
+        arguments: ['@config', '@api', '@output', '@cache']
     local.build:
         class:     '\Platformsh\Cli\Local\LocalBuild'
         arguments: ['@config', '@output', '@shell', '@fs', '@git', 
'@local.dependency_installer']
@@ -31,6 +34,8 @@
     local.project:
         class:     '\Platformsh\Cli\Local\LocalProject'
         arguments: ['@config', '@git']
+    mount:
+        class:     '\Platformsh\Cli\Service\Mount'
     output:
         class:     '\Symfony\Component\Console\Output\ConsoleOutput'
     property_formatter:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/src/Command/CommandBase.php 
new/platformsh-cli-3.23.0/src/Command/CommandBase.php
--- old/platformsh-cli-3.22.3/src/Command/CommandBase.php       2017-11-16 
11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/CommandBase.php       2017-11-24 
17:31:28.000000000 +0100
@@ -555,7 +555,7 @@
      */
     protected function addProjectOption()
     {
-        $this->addOption('project', 'p', InputOption::VALUE_REQUIRED, 'The 
project ID');
+        $this->addOption('project', 'p', InputOption::VALUE_REQUIRED, 'The 
project ID or URL');
         $this->addOption('host', null, InputOption::VALUE_REQUIRED, "The 
project's API hostname");
 
         return $this;
@@ -622,6 +622,7 @@
         }
 
         $this->project = $project;
+        $this->debug('Selected project: ' . $project->id);
 
         return $this->project;
     }
@@ -656,6 +657,7 @@
             }
 
             $this->environment = $environment;
+            $this->debug('Selected environment: ' . $environment->id);
             return;
         }
 
@@ -714,71 +716,6 @@
     }
 
     /**
-     * Parse the project ID and possibly other details from a provided URL.
-     *
-     * @param string $url
-     *     A web UI, API, or public URL of the project.
-     *
-     * @throws \InvalidArgumentException
-     *     If the project ID can't be found in the URL.
-     *
-     * @return array
-     *     An array of containing at least a 'projectId'. Keys 'host',
-     *     'environmentId', and 'appId' will be either null or strings.
-     */
-    protected function parseProjectId($url)
-    {
-        $result = [
-            'projectId' => null,
-            'host' => null,
-            'environmentId' => null,
-            'appId' => null,
-        ];
-
-        // If it's a plain alphanumeric string, then it's an ID already.
-        if (!preg_match('/\W/', $url)) {
-            $result['projectId'] = $url;
-
-            return $result;
-        }
-
-        $this->debug('Parsing URL to determine project ID');
-
-        $host = parse_url($url, PHP_URL_HOST);
-        $path = parse_url($url, PHP_URL_PATH);
-        $site_domains_pattern = '(' . implode('|', array_map('preg_quote', 
$this->config()->get('detection.site_domains'))) . ')';
-        $site_pattern = '/\-\w+\.[a-z]{2}(\-[0-9])?\.' . $site_domains_pattern 
. '$/';
-        if (!strpos($path, '/projects/')
-            && preg_match($site_pattern, $host)) {
-            list($env_project_app,) = explode('.', $host, 2);
-            if (($tripleDashPos = strrpos($env_project_app, '---')) !== false) 
{
-                $env_project_app = substr($env_project_app, $tripleDashPos + 
3);
-            }
-            if (($doubleDashPos = strrpos($env_project_app, '--')) !== false) {
-                $env_project = substr($env_project_app, 0, $doubleDashPos);
-                $result['appId'] = substr($env_project_app, $doubleDashPos + 
2);
-            } else {
-                $env_project = $env_project_app;
-            }
-            if (($dashPos = strrpos($env_project, '-')) !== false) {
-                $result['projectId'] = substr($env_project, $dashPos + 1);
-                $result['environmentId'] = substr($env_project, 0, $dashPos);
-            }
-        } else {
-            $result['host'] = $host;
-            $result['projectId'] = 
basename(preg_replace('#/projects(/\w+)/?.*$#', '$1', $url));
-            if (preg_match('#/environments(/[^/]+)/?.*$#', $url, $matches)) {
-                $result['environmentId'] = rawurldecode(basename($matches[1]));
-            }
-        }
-        if (empty($result['projectId']) || preg_match('/\W/', 
$result['projectId'])) {
-            throw new ConsoleInvalidArgumentException(sprintf('Invalid project 
URL: %s', $url));
-        }
-
-        return $result;
-    }
-
-    /**
      * Offer the user an interactive choice of projects.
      *
      * @param Project[] $projects
@@ -810,9 +747,11 @@
         $projectHost = $input->hasOption('host') ? $input->getOption('host') : 
null;
         $environmentId = null;
 
-        // Parse the project ID.
+        // Identify the project.
         if ($projectId !== null) {
-            $result = $this->parseProjectId($projectId);
+            /** @var \Platformsh\Cli\Service\Identifier $identifier */
+            $identifier = $this->getService('identifier');
+            $result = $identifier->identify($projectId);
             $projectId = $result['projectId'];
             $projectHost = $projectHost ?: $result['host'];
             $environmentId = $result['environmentId'];
@@ -835,7 +774,7 @@
             if (isset($result) && isset($result['appId'])) {
                 $input->setOption('app', $result['appId']);
                 $this->debug(sprintf(
-                    'App name detected from project URL as: %s',
+                    'App name identified as: %s',
                     $input->getOption('app')
                 ));
             }
@@ -877,8 +816,6 @@
             $environmentId = $input->getOption($envOptionName) ?: 
$environmentId;
             $this->selectEnvironment($environmentId, !$envNotRequired);
         }
-
-        $this->debug('Validated input');
     }
 
     /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Integration/IntegrationAddCommand.php 
new/platformsh-cli-3.23.0/src/Command/Integration/IntegrationAddCommand.php
--- old/platformsh-cli-3.22.3/src/Command/Integration/IntegrationAddCommand.php 
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Integration/IntegrationAddCommand.php 
2017-11-24 17:31:28.000000000 +0100
@@ -19,7 +19,11 @@
         $this->addProjectOption()->addNoWaitOption();
         $this->addExample(
             'Add an integration with a GitHub repository',
-            '--type github --repository myuser/example-repo --token 
UFpYS1MzQktjNw --fetch-branches 0'
+            '--type github --repository myuser/example-repo --token 
9218376e14c2797e0d06e8d2f918d45f --fetch-branches 0'
+        );
+        $this->addExample(
+            'Add an integration with a GitLab repository',
+            '--type gitlab --repository mygroup/example-repo --token 
22fe4d70dfbc20e4f668568a0b5422e2 --base-url https://gitlab.example.com'
         );
     }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Integration/IntegrationCommandBase.php 
new/platformsh-cli-3.23.0/src/Command/Integration/IntegrationCommandBase.php
--- 
old/platformsh-cli-3.22.3/src/Command/Integration/IntegrationCommandBase.php    
    2017-11-16 11:12:57.000000000 +0100
+++ 
new/platformsh-cli-3.23.0/src/Command/Integration/IntegrationCommandBase.php    
    2017-11-24 17:31:28.000000000 +0100
@@ -35,6 +35,7 @@
     {
         $types = [
             'github',
+            'gitlab',
             'hipchat',
             'webhook',
             'health.email',
@@ -51,11 +52,28 @@
             'token' => new Field('Token', [
                 'conditions' => ['type' => [
                     'github',
+                    'gitlab',
                     'hipchat',
                     'health.slack',
                 ]],
                 'description' => 'An OAuth token for the integration',
             ]),
+            'base_url' => new Field('Base URL', [
+                'conditions' => ['type' => [
+                    'gitlab',
+                ]],
+                'description' => 'The base URL of the GitLab installation',
+            ]),
+            'project' => new Field('Project', [
+                'optionName' => 'gitlab-project',
+                'conditions' => ['type' => [
+                    'gitlab',
+                ]],
+                'description' => 'The GitLab project (e.g. 
\'namespace/repo\')',
+                'validator' => function ($string) {
+                    return substr_count($string, '/', 1) === 1;
+                },
+            ]),
             'repository' => new Field('Repository', [
                 'conditions' => ['type' => [
                     'github',
@@ -72,6 +90,12 @@
                     return $string;
                 },
             ]),
+            'build_merge_requests' => new BooleanField('Build merge requests', 
[
+                'conditions' => ['type' => [
+                    'gitlab',
+                ]],
+                'description' => 'GitLab: build merge requests as 
environments',
+            ]),
             'build_pull_requests' => new BooleanField('Build pull requests', [
                 'conditions' => ['type' => [
                     'github',
@@ -84,6 +108,13 @@
               ]],
               'description' => 'GitHub: build pull requests based on their 
post-merge state',
             ]),
+            'merge_requests_clone_parent_data' => new BooleanField('Clone data 
for merge requests', [
+                'optionName' => 'merge-requests-clone-parent-data',
+                'conditions' => ['type' => [
+                    'gitlab',
+                ]],
+                'description' => 'GitLab: clone data for merge requests',
+            ]),
             'pull_requests_clone_parent_data' => new BooleanField('Clone data 
for pull requests', [
                 'optionName' => 'pull-requests-clone-parent-data',
                 'conditions' => ['type' => [
@@ -94,8 +125,9 @@
             'fetch_branches' => new BooleanField('Fetch branches', [
                 'conditions' => ['type' => [
                     'github',
+                    'gitlab',
                 ]],
-                'description' => 'GitHub: sync all branches',
+                'description' => 'Whether to sync all branches',
             ]),
             'room' => new Field('HipChat room ID', [
                 'conditions' => ['type' => [
@@ -131,9 +163,18 @@
             'environments' => new ArrayField('Environments', [
                 'conditions' => ['type' => [
                     'webhook',
+                    'hipchat',
                 ]],
                 'default' => ['*'],
-                'description' => 'Generic webhook: the environments relevant 
to the hook',
+                'description' => 'The environments to include',
+            ]),
+            'excluded_environments' => new ArrayField('Excluded environments', 
[
+                'conditions' => ['type' => [
+                    'webhook',
+                    'hipchat',
+                ]],
+                'default' => [],
+                'description' => 'The environments to exclude',
             ]),
             'from_address' => new EmailAddressField('From address', [
                 'conditions' => ['type' => [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Mount/MountCommandBase.php 
new/platformsh-cli-3.23.0/src/Command/Mount/MountCommandBase.php
--- old/platformsh-cli-3.22.3/src/Command/Mount/MountCommandBase.php    
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Mount/MountCommandBase.php    
2017-11-24 17:31:28.000000000 +0100
@@ -7,7 +7,6 @@
 
 abstract class MountCommandBase extends CommandBase
 {
-
     /**
      * Get the remote application config.
      *
@@ -37,68 +36,13 @@
     {
         $options = [];
         foreach ($mounts as $path => $id) {
-            $normalized = $this->normalizeMountPath($path);
-            $options[$normalized] = sprintf('<question>%s</question>: %s', 
$normalized, trim($id, '/'));
+            $options[$path] = sprintf('<question>%s</question>: %s', $path, 
trim($id, '/'));
         }
 
         return $options;
     }
 
     /**
-     * Get the path under '.platform/local/shared' for a mount.
-     *
-     * @param string $path
-     * @param array  $mounts
-     *
-     * @return string|false
-     */
-    protected function getSharedPath($path, array $mounts)
-    {
-        $normalized = $this->normalizeMountPath($path);
-        foreach ($mounts as $path => $uri) {
-            if ($this->normalizeMountPath($path) === $normalized
-                && preg_match('#^shared:files/(.+)$#', $uri, $matches)) {
-                return trim($matches[1], '/');
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Normalize a path to a mount.
-     *
-     * @param string $path
-     *
-     * @return string
-     */
-    protected function normalizeMountPath($path)
-    {
-        return trim(trim($path), '/');
-    }
-
-    /**
-     * Validate and normalize a path to a mount.
-     *
-     * @param string $inputPath
-     * @param array  $mounts
-     *
-     * @return string
-     *   The normalized mount path.
-     */
-    protected function validateMountPath($inputPath, array $mounts)
-    {
-        $normalized = trim(trim($inputPath), '/');
-        foreach (array_keys($mounts) as $path) {
-            if (trim(trim($path), '/') === $normalized) {
-                return $normalized;
-            }
-        }
-
-        throw new \InvalidArgumentException(sprintf('Mount not found: 
<error>%s</error>', $inputPath));
-    }
-
-    /**
      * Validate a directory argument.
      *
      * @param string $directory
@@ -122,21 +66,15 @@
      * @param string $mountPath
      * @param string $localPath
      * @param bool   $up
-     * @param bool   $delete
+     * @param array  $options
      */
-    protected function runSync($sshUrl, $mountPath, $localPath, $up, $delete = 
false)
+    protected function runSync($sshUrl, $mountPath, $localPath, $up, array 
$options = [])
     {
         /** @var \Platformsh\Cli\Service\Shell $shell */
         $shell = $this->getService('shell');
 
         $mountPathAbsolute = $this->getAppDir($sshUrl) . '/' . $mountPath;
 
-        if ($up) {
-            $this->stdErr->writeln(sprintf('Uploading files from 
<info>%s</info> to the remote mount <info>%s</info>', $localPath, 
$mountPathAbsolute));
-        } else {
-            $this->stdErr->writeln(sprintf('Downloading files from the remote 
mount <info>%s</info> to <info>%s</info>', $mountPathAbsolute, $localPath));
-        }
-
         $params = ['rsync', '--archive', '--compress', '--human-readable'];
 
         if ($this->stdErr->isVeryVerbose()) {
@@ -153,9 +91,16 @@
             $params[] = $localPath;
         }
 
-        if ($delete) {
+        if (!empty($options['delete'])) {
             $params[] = '--delete';
         }
+        foreach (['exclude', 'include'] as $option) {
+            if (!empty($options[$option])) {
+                foreach ($options[$option] as $value) {
+                    $params[] = '--' . $option . '=' . $value;
+                }
+            }
+        }
 
         $start = microtime(true);
         $shell->execute($params, null, true, false, [], null);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Mount/MountDownloadCommand.php 
new/platformsh-cli-3.23.0/src/Command/Mount/MountDownloadCommand.php
--- old/platformsh-cli-3.22.3/src/Command/Mount/MountDownloadCommand.php        
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Mount/MountDownloadCommand.php        
2017-11-24 17:31:28.000000000 +0100
@@ -22,6 +22,8 @@
             ->addOption('mount', 'm', InputOption::VALUE_REQUIRED, 'The mount 
(as an app-relative path)')
             ->addOption('target', null, InputOption::VALUE_REQUIRED, 'The 
directory to which files will be downloaded')
             ->addOption('delete', null, InputOption::VALUE_NONE, 'Whether to 
delete extraneous files in the target directory')
+            ->addOption('exclude', null, 
InputOption::VALUE_IS_ARRAY|InputOption::VALUE_REQUIRED, 'File(s) to exclude 
from the download (pattern)')
+            ->addOption('include', null, 
InputOption::VALUE_IS_ARRAY|InputOption::VALUE_REQUIRED, 'File(s) to include in 
the download (pattern)')
             ->addOption('refresh', null, InputOption::VALUE_NONE, 'Whether to 
refresh the cache');
         $this->addProjectOption();
         $this->addEnvironmentOption();
@@ -46,6 +48,9 @@
 
             return 1;
         }
+        /** @var \Platformsh\Cli\Service\Mount $mountService */
+        $mountService = $this->getService('mount');
+        $mounts = $mountService->normalizeMounts($appConfig['mounts']);
 
         /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */
         $questionHelper = $this->getService('question_helper');
@@ -53,10 +58,10 @@
         $fs = $this->getService('fs');
 
         if ($input->getOption('mount')) {
-            $mountPath = $this->validateMountPath($input->getOption('mount'), 
$appConfig['mounts']);
+            $mountPath = 
$mountService->validateMountPath($input->getOption('mount'), $mounts);
         } elseif ($input->isInteractive()) {
             $mountPath = $questionHelper->choose(
-                $this->getMountsAsOptions($appConfig['mounts']),
+                $this->getMountsAsOptions($mounts),
                 'Enter a number to choose a mount to download from:'
             );
         } else {
@@ -70,9 +75,10 @@
         if ($input->getOption('target')) {
             $target = $input->getOption('target');
         } elseif ($projectRoot = $this->getProjectRoot()) {
-            if ($sharedPath = $this->getSharedPath($mountPath, 
$appConfig['mounts'])) {
-                if (file_exists($projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedPath)) {
-                    $defaultTarget = $projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedPath;
+            $sharedMounts = $mountService->getSharedFileMounts($appConfig);
+            if (isset($sharedMounts[$mountPath])) {
+                if (file_exists($projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedMounts[$mountPath])) {
+                    $defaultTarget = $projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedMounts[$mountPath];
                 }
             }
 
@@ -107,13 +113,21 @@
 
         $this->validateDirectory($target, true);
 
-        $confirmText = "\nThis will <options=bold>add, replace, and delete</> 
files in the local directory '<comment>" . $fs->formatPathForDisplay($target) . 
"</comment>'."
-            . "\n\nAre you sure you want to continue?";
+        $confirmText = sprintf(
+            "\nDownloading files from the remote mount <comment>%s</comment> 
to <comment>%s</comment>"
+            . "\n\nAre you sure you want to continue?",
+            $mountPath,
+            $fs->formatPathForDisplay($target)
+        );
         if (!$questionHelper->confirm($confirmText)) {
             return 1;
         }
 
-        $this->runSync($sshUrl, $mountPath, $target, false, (bool) 
$input->getOption('delete'));
+        $this->runSync($sshUrl, $mountPath, $target, false, [
+            'delete' => $input->getOption('delete'),
+            'exclude' => $input->getOption('exclude'),
+            'include' => $input->getOption('include'),
+        ]);
 
         return 0;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Mount/MountListCommand.php 
new/platformsh-cli-3.23.0/src/Command/Mount/MountListCommand.php
--- old/platformsh-cli-3.22.3/src/Command/Mount/MountListCommand.php    
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Mount/MountListCommand.php    
2017-11-24 17:31:28.000000000 +0100
@@ -39,25 +39,27 @@
 
         $appConfig = $this->getAppConfig($sshUrl, (bool) 
$input->getOption('refresh'));
 
-        $mounts = $appConfig['mounts'];
-        if (empty($mounts)) {
+        if (empty($appConfig['mounts'])) {
             $this->stdErr->writeln(sprintf('The app "%s" doesn\'t define any 
mounts.', $appConfig['name']));
 
-            return 0;
+            return 1;
         }
+        /** @var \Platformsh\Cli\Service\Mount $mountService */
+        $mountService = $this->getService('mount');
+        $mounts = $mountService->normalizeMounts($appConfig['mounts']);
 
         if ($input->getOption('paths')) {
-            foreach (array_keys($mounts) as $path) {
-                $output->writeln($this->normalizeMountPath($path));
-            }
+            $output->writeln(array_keys($mounts));
 
             return 0;
         }
 
-        $header = ['Path', 'Definition'];
+        $header = ['Mount path', 'Definition'];
         $rows = [];
+        /** @var \Platformsh\Cli\Service\PropertyFormatter $formatter */
+        $formatter = $this->getService('property_formatter');
         foreach ($mounts as $path => $definition) {
-            $rows[] = [$this->normalizeMountPath($path), $definition];
+            $rows[] = [$path, $formatter->format($definition)];
         }
 
         /** @var \Platformsh\Cli\Service\Table $table */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Mount/MountUploadCommand.php 
new/platformsh-cli-3.23.0/src/Command/Mount/MountUploadCommand.php
--- old/platformsh-cli-3.22.3/src/Command/Mount/MountUploadCommand.php  
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Mount/MountUploadCommand.php  
2017-11-24 17:31:28.000000000 +0100
@@ -22,6 +22,8 @@
             ->addOption('source', null, InputOption::VALUE_REQUIRED, 'A 
directory containing files to upload')
             ->addOption('mount', 'm', InputOption::VALUE_REQUIRED, 'The mount 
(as an app-relative path)')
             ->addOption('delete', null, InputOption::VALUE_NONE, 'Whether to 
delete extraneous files in the mount')
+            ->addOption('exclude', null, 
InputOption::VALUE_IS_ARRAY|InputOption::VALUE_REQUIRED, 'File(s) to exclude 
from the upload (pattern)')
+            ->addOption('include', null, 
InputOption::VALUE_IS_ARRAY|InputOption::VALUE_REQUIRED, 'File(s) to include in 
the upload (pattern)')
             ->addOption('refresh', null, InputOption::VALUE_NONE, 'Whether to 
refresh the cache');
         $this->addProjectOption();
         $this->addEnvironmentOption();
@@ -46,6 +48,9 @@
 
             return 1;
         }
+        /** @var \Platformsh\Cli\Service\Mount $mountService */
+        $mountService = $this->getService('mount');
+        $mounts = $mountService->normalizeMounts($appConfig['mounts']);
 
         /** @var \Platformsh\Cli\Service\QuestionHelper $questionHelper */
         $questionHelper = $this->getService('question_helper');
@@ -53,10 +58,10 @@
         $fs = $this->getService('fs');
 
         if ($input->getOption('mount')) {
-            $mountPath = $this->validateMountPath($input->getOption('mount'), 
$appConfig['mounts']);
+            $mountPath = 
$mountService->validateMountPath($input->getOption('mount'), $mounts);
         } elseif ($input->isInteractive()) {
             $mountPath = $questionHelper->choose(
-                $this->getMountsAsOptions($appConfig['mounts']),
+                $this->getMountsAsOptions($mounts),
                 'Enter a number to choose a mount to upload to:'
             );
         } else {
@@ -70,9 +75,10 @@
         if ($input->getOption('source')) {
             $source = $input->getOption('source');
         } elseif ($projectRoot = $this->getProjectRoot()) {
-            if ($sharedPath = $this->getSharedPath($mountPath, 
$appConfig['mounts'])) {
-                if (file_exists($projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedPath)) {
-                    $defaultSource = $projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedPath;
+            $sharedMounts = $mountService->getSharedFileMounts($appConfig);
+            if (isset($sharedMounts[$mountPath])) {
+                if (file_exists($projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedMounts[$mountPath])) {
+                    $defaultSource = $projectRoot . '/' . 
$this->config()->get('local.shared_dir') . '/' . $sharedMounts[$mountPath];
                 }
             }
 
@@ -107,14 +113,21 @@
 
         $this->validateDirectory($source);
 
-        $confirmText = "\nThis will <options=bold>add, replace, and delete</> 
files in the remote mount '<info>$mountPath</info>'."
-            . "\n\nAre you sure you want to continue?";
+        $confirmText = sprintf(
+            "\nUploading files from <comment>%s</comment> to the remote mount 
<comment>%s</comment>"
+            . "\n\nAre you sure you want to continue?",
+            $fs->formatPathForDisplay($source),
+            $mountPath
+        );
         if (!$questionHelper->confirm($confirmText)) {
             return 1;
         }
 
-        $this->runSync($sshUrl, $mountPath, $source, true, (bool) 
$input->getOption('delete'));
-
+        $this->runSync($sshUrl, $mountPath, $source, true, [
+            'delete' => $input->getOption('delete'),
+            'exclude' => $input->getOption('exclude'),
+            'include' => $input->getOption('include'),
+        ]);
         return 0;
     }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Project/ProjectGetCommand.php 
new/platformsh-cli-3.23.0/src/Command/Project/ProjectGetCommand.php
--- old/platformsh-cli-3.22.3/src/Command/Project/ProjectGetCommand.php 
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Project/ProjectGetCommand.php 
2017-11-24 17:31:28.000000000 +0100
@@ -202,7 +202,9 @@
                 throw new InvalidArgumentException('No project specified');
             }
         } else {
-            $result = $this->parseProjectId($projectId);
+            /** @var \Platformsh\Cli\Service\Identifier $identifier */
+            $identifier = $this->getService('identifier');
+            $result = $identifier->identify($projectId);
             $projectId = $result['projectId'];
             $host = $host ?: $result['host'];
             $environmentId = $environmentId ?: $result['environmentId'];
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/platformsh-cli-3.22.3/src/Command/Project/ProjectSetRemoteCommand.php 
new/platformsh-cli-3.23.0/src/Command/Project/ProjectSetRemoteCommand.php
--- old/platformsh-cli-3.22.3/src/Command/Project/ProjectSetRemoteCommand.php   
2017-11-16 11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Command/Project/ProjectSetRemoteCommand.php   
2017-11-24 17:31:28.000000000 +0100
@@ -20,8 +20,12 @@
     protected function execute(InputInterface $input, OutputInterface $output)
     {
         $projectId = $input->getArgument('project');
-        $result = $this->parseProjectId($projectId);
-        $project = $this->selectProject($result['projectId'] ?: $projectId);
+
+        /** @var \Platformsh\Cli\Service\Identifier $identifier */
+        $identifier = $this->getService('identifier');
+        $result = $identifier->identify($projectId);
+
+        $project = $this->selectProject($result['projectId']);
 
         /** @var \Platformsh\Cli\Service\Git $git */
         $git = $this->getService('git');
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/src/Local/LocalApplication.php 
new/platformsh-cli-3.23.0/src/Local/LocalApplication.php
--- old/platformsh-cli-3.22.3/src/Local/LocalApplication.php    2017-11-16 
11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Local/LocalApplication.php    2017-11-24 
17:31:28.000000000 +0100
@@ -4,6 +4,7 @@
 use Platformsh\Cli\Service\Config;
 use Platformsh\Cli\Exception\InvalidConfigException;
 use Platformsh\Cli\Local\BuildFlavor\BuildFlavorInterface;
+use Platformsh\Cli\Service\Mount;
 use Symfony\Component\Finder\Finder;
 use Symfony\Component\Yaml\Exception\ParseException;
 use Symfony\Component\Yaml\Parser;
@@ -15,6 +16,7 @@
     protected $config;
     protected $sourceDir;
     protected $cliConfig;
+    protected $mount;
 
     /**
      * @param string      $appRoot
@@ -29,6 +31,7 @@
         $this->cliConfig = $cliConfig ?: new Config();
         $this->appRoot = $appRoot;
         $this->sourceDir = $sourceDir ?: $appRoot;
+        $this->mount = new Mount();
     }
 
     /**
@@ -144,22 +147,10 @@
      * Get a list of shared file mounts configured for the app.
      *
      * @return array
-     *     An array of shared file mount paths, keyed by the path in the app.
-     *     Leading and trailing slashes are stripped.
      */
     public function getSharedFileMounts()
     {
-        $sharedFileMounts = [];
-        $appConfig = $this->getConfig();
-        if (!empty($appConfig['mounts'])) {
-            foreach ($appConfig['mounts'] as $path => $uri) {
-                if (preg_match('#^shared:files/(.+)$#', $uri, $matches)) {
-                    $sharedFileMounts[trim($path, '/')] = trim($matches[1], 
'/');
-                }
-            }
-        }
-
-        return $sharedFileMounts;
+        return $this->mount->getSharedFileMounts($this->getConfig());
     }
 
     /**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/src/Service/Api.php 
new/platformsh-cli-3.23.0/src/Service/Api.php
--- old/platformsh-cli-3.22.3/src/Service/Api.php       2017-11-16 
11:12:57.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Service/Api.php       2017-11-24 
17:31:28.000000000 +0100
@@ -3,6 +3,7 @@
 namespace Platformsh\Cli\Service;
 
 use Doctrine\Common\Cache\CacheProvider;
+use GuzzleHttp\ClientInterface;
 use Platformsh\Cli\Event\EnvironmentsChangedEvent;
 use Platformsh\Cli\Util\NestedArrayUtil;
 use Platformsh\Client\Connection\Connector;
@@ -229,7 +230,7 @@
 
             $this->cache->save($cacheKey, $cachedProjects, 
$this->config->get('api.projects_ttl'));
         } else {
-            $guzzleClient = $this->getClient()->getConnector()->getClient();
+            $guzzleClient = $this->getHttpClient();
             foreach ((array) $cached as $id => $data) {
                 $projects[$id] = new Project($data, $data['_endpoint'], 
$guzzleClient);
             }
@@ -273,7 +274,7 @@
                 $this->cache->save($cacheKey, $toCache, 
$this->config->get('api.projects_ttl'));
             }
         } else {
-            $guzzleClient = $this->getClient()->getConnector()->getClient();
+            $guzzleClient = $this->getHttpClient();
             $baseUrl = $cached['_endpoint'];
             unset($cached['_endpoint']);
             $project = new Project($cached, $baseUrl, $guzzleClient);
@@ -325,7 +326,7 @@
         } else {
             $environments = [];
             $endpoint = $project->getUri();
-            $guzzleClient = $this->getClient()->getConnector()->getClient();
+            $guzzleClient = $this->getHttpClient();
             foreach ((array) $cached as $id => $data) {
                 $environments[$id] = new Environment($data, $endpoint, 
$guzzleClient, true);
             }
@@ -635,4 +636,14 @@
 
         return $result;
     }
+
+    /**
+     * Get the HTTP client.
+     *
+     * @return ClientInterface
+     */
+    public function getHttpClient()
+    {
+        return $this->getClient(false)->getConnector()->getClient();
+    }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/src/Service/Identifier.php 
new/platformsh-cli-3.23.0/src/Service/Identifier.php
--- old/platformsh-cli-3.22.3/src/Service/Identifier.php        1970-01-01 
01:00:00.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Service/Identifier.php        2017-11-24 
17:31:28.000000000 +0100
@@ -0,0 +1,177 @@
+<?php
+/**
+ * @file
+ * Finds the correct project and environment for a given URL/string.
+ */
+
+namespace Platformsh\Cli\Service;
+
+use Doctrine\Common\Cache\Cache;
+use GuzzleHttp\Exception\RequestException;
+use Symfony\Component\Console\Exception\InvalidArgumentException;
+use Symfony\Component\Console\Output\ConsoleOutput;
+use Symfony\Component\Console\Output\NullOutput;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Identifier
+{
+    private $config;
+    private $api;
+    private $stdErr;
+    private $cache;
+
+    /**
+     * Constructor.
+     *
+     * @param \Platformsh\Cli\Service\Config|null                    $config
+     * @param \Platformsh\Cli\Service\Api|null                       $api
+     * @param \Symfony\Component\Console\Output\OutputInterface|null $output
+     * @param \Doctrine\Common\Cache\Cache|null                      $cache
+     */
+    public function __construct(Config $config = null, Api $api = null, 
OutputInterface $output = null, Cache $cache = null)
+    {
+        $this->config = $config ?: new Config();
+        $this->api = $api ?: new Api();
+        $output = $output ?: new NullOutput();
+        $this->stdErr = $output instanceof ConsoleOutput ? 
$output->getErrorOutput() : $output;
+        $this->cache = $cache;
+    }
+
+    /**
+     * Identify a project from an ID or URL.
+     *
+     * @param string $url
+     *
+     * @return array
+     *   An array containing keys 'projectId', 'environmentId', 'host', and
+     *   'appId'. At least the 'projectId' will be populated.
+     */
+    public function identify($url)
+    {
+        $result = $this->parseProjectId($url);
+        if (empty($result['projectId']) && strpos($url, '.') !== false) {
+            $result = $this->identifyFromHeaders($url);
+        }
+        if (empty($result['projectId'])) {
+            throw new InvalidArgumentException('Failed to identify project ID 
from URL: <error>' . $url . '</error>');
+        }
+
+        return $result + ['environmentId' => null, 'host' => null, 'appId' => 
null];
+    }
+
+    /**
+     * Parse the project ID and possibly other details from a provided URL.
+     *
+     * @param string $url
+     *   A web UI, API, or public URL of the project.
+     *
+     * @return array
+     */
+    private function parseProjectId($url)
+    {
+        $result = [];
+
+        // If it's a plain alphanumeric string, then it's an ID already.
+        if (!preg_match('/\W/', $url)) {
+            $result['projectId'] = $url;
+
+            return $result;
+        }
+
+        $urlParts = parse_url($url);
+        if ($urlParts === false || empty($urlParts['host'])) {
+            return $result;
+        }
+
+        $this->debug('Parsing URL to determine project ID: ' . $url);
+
+        $host = $urlParts['host'];
+        $path = isset($urlParts['path']) ? $urlParts['path'] : '';
+        $fragment = isset($urlParts['fragment']) ? $urlParts['fragment'] : '';
+
+        $site_domains_pattern = '(' . implode('|', array_map('preg_quote', 
$this->config->get('detection.site_domains'))) . ')';
+        $site_pattern = '/\-\w+\.[a-z]{2}(\-[0-9])?\.' . $site_domains_pattern 
. '$/';
+        if (strpos($path, '/projects/') !== false || strpos($fragment, 
'/projects/') !== false) {
+            $result['host'] = $host;
+            $result['projectId'] = 
basename(preg_replace('#/projects(/\w+)/?.*$#', '$1', $url));
+            if (preg_match('#/environments(/[^/]+)/?.*$#', $url, $matches)) {
+                $result['environmentId'] = rawurldecode(basename($matches[1]));
+            }
+        } elseif (preg_match($site_pattern, $host)) {
+            list($env_project_app,) = explode('.', $host, 2);
+            if (($tripleDashPos = strrpos($env_project_app, '---')) !== false) 
{
+                $env_project_app = substr($env_project_app, $tripleDashPos + 
3);
+            }
+            if (($doubleDashPos = strrpos($env_project_app, '--')) !== false) {
+                $env_project = substr($env_project_app, 0, $doubleDashPos);
+                $result['appId'] = substr($env_project_app, $doubleDashPos + 
2);
+            } else {
+                $env_project = $env_project_app;
+            }
+            if (($dashPos = strrpos($env_project, '-')) !== false) {
+                $result['projectId'] = substr($env_project, $dashPos + 1);
+                $result['environmentId'] = substr($env_project, 0, $dashPos);
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * Identify a project and environment from a URL's response headers.
+     *
+     * @param string $url
+     *
+     * @return array
+     */
+    private function identifyFromHeaders($url)
+    {
+        if (!strpos($url, '.')) {
+            throw new \InvalidArgumentException('Invalid URL: ' . $url);
+        }
+        if (strpos($url, '//') === false) {
+            $url = 'https://' . $url;
+        }
+        $result = ['projectId' => null, 'environmentId' => null];
+        $cluster = $this->getClusterHeader($url);
+        if (!empty($cluster)) {
+            $this->debug('Identified project cluster: ' . $cluster);
+            list($result['projectId'], $result['environmentId']) = 
explode('-', $cluster, 2);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Get a project cluster from its URL.
+     *
+     * @param string $url
+     *
+     * @return string
+     */
+    private function getClusterHeader($url)
+    {
+        $cacheKey = 'project-cluster:' . $url;
+        $cluster = $this->cache ? $this->cache->fetch($cacheKey) : false;
+        if ($cluster === false) {
+            $this->debug('Making a HEAD request to identify project from URL: 
' . $url);
+            try {
+                $response = $this->api->getHttpClient()->head($url, ['auth' => 
false]);
+                $cluster = 
$response->getHeader($this->config->get('service.header_prefix') . '-cluster');
+                $this->cache->save($cacheKey, $cluster, 86400);
+            } catch (RequestException $e) {
+                $this->debug($e->getMessage());
+            }
+        }
+
+        return $cluster;
+    }
+
+    /**
+     * @param string $message
+     */
+    private function debug($message)
+    {
+        $this->stdErr->writeln('<options=reverse>DEBUG</> ' . $message, 
OutputInterface::VERBOSITY_DEBUG);
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/platformsh-cli-3.22.3/src/Service/Mount.php 
new/platformsh-cli-3.23.0/src/Service/Mount.php
--- old/platformsh-cli-3.22.3/src/Service/Mount.php     1970-01-01 
01:00:00.000000000 +0100
+++ new/platformsh-cli-3.23.0/src/Service/Mount.php     2017-11-24 
17:31:28.000000000 +0100
@@ -0,0 +1,110 @@
+<?php
+/**
+ * @file
+ * Service to help with mounts.
+ */
+
+namespace Platformsh\Cli\Service;
+
+class Mount
+{
+    /**
+     * Get a list of shared file mounts configured for an app.
+     *
+     * @param array $appConfig The app configuration.
+     *
+     * @return array
+     *   An array of shared file paths, keyed by the mount path. Leading and
+     *   trailing slashes are stripped. An empty shared path defaults to
+     *   'files'.
+     */
+    public function getSharedFileMounts(array $appConfig)
+    {
+        $sharedFileMounts = [];
+        if (!empty($appConfig['mounts'])) {
+            foreach ($this->normalizeMounts($appConfig['mounts']) as $path => 
$definition) {
+                if (isset($definition['source_path'])) {
+                    $sharedFileMounts[$path] = $definition['source_path'] ?: 
'files';
+                }
+            }
+        }
+
+        return $sharedFileMounts;
+    }
+
+    /**
+     * Normalize a list of mounts.
+     *
+     * @param array $mounts
+     *
+     * @return array
+     */
+    public function normalizeMounts(array $mounts)
+    {
+        $normalized = [];
+        foreach ($mounts as $path => $definition) {
+            $normalized[$this->normalizeRelativePath($path)] = 
$this->normalizeDefinition($definition);
+        }
+
+        return $normalized;
+    }
+
+    /**
+     * Validate and normalize a path to a mount.
+     *
+     * @param string $inputPath
+     * @param array  $mounts
+     *
+     * @return string
+     *   The normalized mount path.
+     */
+    public function validateMountPath($inputPath, array $mounts)
+    {
+        $normalized = $this->normalizeRelativePath($inputPath);
+        if (isset($mounts[$normalized])) {
+            return $normalized;
+        }
+
+        throw new \InvalidArgumentException(sprintf('Mount not found: 
<error>%s</error>', $inputPath));
+    }
+
+    /**
+     * Normalize a path to a mount.
+     *
+     * @param string $path
+     *
+     * @return string
+     */
+    private function normalizeRelativePath($path)
+    {
+        return trim(trim($path), '/');
+    }
+
+    /**
+     * Normalize a mount definition.
+     *
+     * @param array|string $definition
+     *
+     * @return array
+     *   An array containing at least 'source', and probably 'source_path'.
+     */
+    private function normalizeDefinition($definition)
+    {
+        if (!is_array($definition)) {
+            if (!is_string($definition) || strpos($definition, 'shared:files') 
=== false) {
+                throw new \RuntimeException('Failed to parse mount definition: 
' . json_encode($definition));
+            }
+            $definition = [
+                'source' => 'local',
+                'source_path' => str_replace('shared:files', '', $definition),
+            ];
+        } elseif (!isset($definition['source'])) {
+            throw new \InvalidArgumentException('Invalid mount definition: ' . 
json_encode($definition));
+        }
+        if (isset($definition['source_path'])) {
+            $definition['source_path'] = 
$this->normalizeRelativePath($definition['source_path']);
+        }
+
+        return $definition;
+    }
+}

++++++ 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     2017-11-17 03:10:21.750250969 +0100
+++ new/vendor/autoload.php     2017-11-29 04:34:08.486671140 +0100
@@ -4,4 +4,4 @@
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInit9af1103173d4746089e91b605155fbbc::getLoader();
+return ComposerAutoloaderInite17779ccbc2cb04617d6385149e1e678::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       2017-11-17 03:10:21.750250969 
+0100
+++ new/vendor/composer/autoload_real.php       2017-11-29 04:34:08.486671140 
+0100
@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInit9af1103173d4746089e91b605155fbbc
+class ComposerAutoloaderInite17779ccbc2cb04617d6385149e1e678
 {
     private static $loader;
 
@@ -19,15 +19,15 @@
             return self::$loader;
         }
 
-        
spl_autoload_register(array('ComposerAutoloaderInit9af1103173d4746089e91b605155fbbc',
 'loadClassLoader'), true, true);
+        
spl_autoload_register(array('ComposerAutoloaderInite17779ccbc2cb04617d6385149e1e678',
 'loadClassLoader'), true, true);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader();
-        
spl_autoload_unregister(array('ComposerAutoloaderInit9af1103173d4746089e91b605155fbbc',
 'loadClassLoader'));
+        
spl_autoload_unregister(array('ComposerAutoloaderInite17779ccbc2cb04617d6385149e1e678',
 '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\ComposerStaticInit9af1103173d4746089e91b605155fbbc::getInitializer($loader));
+            
call_user_func(\Composer\Autoload\ComposerStaticInite17779ccbc2cb04617d6385149e1e678::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\ComposerStaticInit9af1103173d4746089e91b605155fbbc::$files;
+            $includeFiles = 
Composer\Autoload\ComposerStaticInite17779ccbc2cb04617d6385149e1e678::$files;
         } else {
             $includeFiles = require __DIR__ . '/autoload_files.php';
         }
         foreach ($includeFiles as $fileIdentifier => $file) {
-            composerRequire9af1103173d4746089e91b605155fbbc($fileIdentifier, 
$file);
+            composerRequiree17779ccbc2cb04617d6385149e1e678($fileIdentifier, 
$file);
         }
 
         return $loader;
     }
 }
 
-function composerRequire9af1103173d4746089e91b605155fbbc($fileIdentifier, 
$file)
+function composerRequiree17779ccbc2cb04617d6385149e1e678($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     2017-11-17 03:10:21.750250969 
+0100
+++ new/vendor/composer/autoload_static.php     2017-11-29 04:34:08.486671140 
+0100
@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInit9af1103173d4746089e91b605155fbbc
+class ComposerStaticInite17779ccbc2cb04617d6385149e1e678
 {
     public static $files = array (
         '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . 
'/symfony/polyfill-mbstring/bootstrap.php',
@@ -188,9 +188,9 @@
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = 
ComposerStaticInit9af1103173d4746089e91b605155fbbc::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = 
ComposerStaticInit9af1103173d4746089e91b605155fbbc::$prefixDirsPsr4;
-            $loader->classMap = 
ComposerStaticInit9af1103173d4746089e91b605155fbbc::$classMap;
+            $loader->prefixLengthsPsr4 = 
ComposerStaticInite17779ccbc2cb04617d6385149e1e678::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = 
ComposerStaticInite17779ccbc2cb04617d6385149e1e678::$prefixDirsPsr4;
+            $loader->classMap = 
ComposerStaticInite17779ccbc2cb04617d6385149e1e678::$classMap;
 
         }, null, ClassLoader::class);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/composer/installed.json 
new/vendor/composer/installed.json
--- old/vendor/composer/installed.json  2017-11-17 03:10:21.166245724 +0100
+++ new/vendor/composer/installed.json  2017-11-29 04:34:07.866665802 +0100
@@ -657,17 +657,17 @@
     },
     {
         "name": "platformsh/client",
-        "version": "v0.12.0",
-        "version_normalized": "0.12.0.0",
+        "version": "v0.12.1",
+        "version_normalized": "0.12.1.0",
         "source": {
             "type": "git",
             "url": "https://github.com/platformsh/platformsh-client-php.git";,
-            "reference": "e5ce468ddc35d8a95fff79579a17b076cd5831c4"
+            "reference": "945ba687f110c3c74e8c250b1b4afd2d03062c7c"
         },
         "dist": {
             "type": "zip",
-            "url": 
"https://api.github.com/repos/platformsh/platformsh-client-php/zipball/e5ce468ddc35d8a95fff79579a17b076cd5831c4";,
-            "reference": "e5ce468ddc35d8a95fff79579a17b076cd5831c4",
+            "url": 
"https://api.github.com/repos/platformsh/platformsh-client-php/zipball/945ba687f110c3c74e8c250b1b4afd2d03062c7c";,
+            "reference": "945ba687f110c3c74e8c250b1b4afd2d03062c7c",
             "shasum": ""
         },
         "require": {
@@ -680,7 +680,7 @@
         "require-dev": {
             "phpunit/phpunit": "~4.5"
         },
-        "time": "2017-09-20T08:28:37+00:00",
+        "time": "2017-11-16T12:15:47+00:00",
         "type": "library",
         "extra": {
             "patches": {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/platformsh/client/src/Model/Integration.php 
new/vendor/platformsh/client/src/Model/Integration.php
--- old/vendor/platformsh/client/src/Model/Integration.php      2017-09-20 
10:28:37.000000000 +0200
+++ new/vendor/platformsh/client/src/Model/Integration.php      2017-11-16 
13:15:47.000000000 +0100
@@ -19,6 +19,7 @@
       'bitbucket',
       'hipchat',
       'github',
+      'gitlab',
       'webhook',
       'health.email',
       'health.pagerduty',


Reply via email to