{"action":"created","comment":{"url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/comments/57739668","id":57739668,"diff_hunk":"@@ -0,0 +1,433 @@\n+<?php\n+\n+namespace Pim\\Behat\\Decorator\\GridDecorator;\n+\n+use Behat\\Mink\\Driver\\DriverInterface;\n+use Behat\\Mink\\Driver\\Selenium2Driver;\n+use Behat\\Mink\\Element\\NodeElement;\n+use Context\\Spin\\SpinCapableTrait;\n+use Context\\Spin\\TimeoutException;\n+use Pim\\Behat\\Decorator\\ElementDecorator;\n+\n+/**\n+ * Decorator to manipulate activated filters\n+ *\n+ * @author    Samir Boulil <samir.boulil@akeneo.com>\n+ * @copyright 2016 Akeneo SAS (http://www.akeneo.com)\n+ * @license   http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)\n+ */\n+class FilterDecorator extends ElementDecorator\n+{\n+    use SpinCapableTrait;\n+\n+    const FILTER_CONTAINS         = 1;\n+    const FILTER_DOES_NOT_CONTAIN = 2;\n+    const FILTER_IS_EQUAL_TO      = 3;\n+    const FILTER_STARTS_WITH      = 4;\n+    const FILTER_ENDS_WITH        = 5;\n+    const FILTER_IS_EMPTY         = 'empty';\n+    const FILTER_IN_LIST          = 'in';\n+\n+    protected $selectors = [\n+        'Filters'                  => '.filter-box',\n+        'Filters list'             => 'div.filter-list', // 'div' is mandatory here\n+        'Grid toolbar'             => 'div.grid-toolbar',\n+        'Filter list autocomplete' => '#select2-drop .select2-results',\n+    ];\n+\n+    /**\n+     * Show a filter from the management list\n+     *\n+     * @param string $filterName\n+     */\n+    public function showFilter($filterName)\n+    {\n+        $toBeShown = false;\n+\n+        try {\n+            if (!$this->getFilter($filterName)->isVisible()) {\n+                $toBeShown = true;\n+            }\n+        } catch (TimeoutException $e) {\n+            $toBeShown = true;\n+        }\n+\n+        if ($toBeShown) {\n+            $this->searchInFilterList($filterName);\n+            $filter = $this->getFilterFromFilterList($filterName)->find('css', 'input');\n+            $filter->check();\n+        }\n+    }\n+\n+    /**\n+     * Hide a filter from the management list\n+     *\n+     * @param string $filterName\n+     */\n+    public function hideFilter($filterName)\n+    {\n+        $toHide = false;\n+        try {\n+            if ($this->getFilter($filterName)->isVisible()) {\n+                $toHide = true;\n+            }\n+\n+        } catch (TimeoutException $e) {\n+            $toHide = false;\n+        }\n+\n+        if ($toHide) {\n+            $this->searchInFilterList($filterName);\n+            $filter = $this->getFilterFromFilterList($filterName)->find('css', 'input');\n+            $filter->uncheck();\n+        }\n+    }\n+\n+    /**\n+     * @param string $filterName\n+     *\n+     * @return bool\n+     */\n+    public function isFilterAvailable($filterName)\n+    {\n+        $this->showFilterList();\n+\n+        $filterElement = $this\n+            ->getFilterList()\n+            ->find('css', sprintf('label:contains(\"%s\")', $filterName));\n+\n+        return null !== $filterElement;\n+    }\n+\n+    /**\n+     * Click on a filter in filter management list\n+     *\n+     * @param string $filterName\n+     *\n+     * @return NodeElement\n+     */\n+    public function getFilterFromFilterList($filterName)\n+    {\n+        $this->showFilterList();\n+        return $this->spin(function () use ($filterName) {\n+            return $this->getFilterList()\n+                ->find('css', sprintf('label:contains(\"%s\")', $filterName));\n+        }, sprintf('Impossible to find filter \"%s\"', $filterName));\n+    }\n+\n+    /**\n+     * Search for a filter in the list of filters\n+     *\n+     * @param $filterName\n+     *\n+     * @throws \\Context\\Spin\\TimeoutException\n+     */\n+    public function searchInFilterList($filterName)\n+    {\n+        $this->showFilterList();\n+        $manageFilters = $this->getFilterList();\n+        $searchField = $this->spin(function () use ($manageFilters) {\n+            return $manageFilters->find('css', 'input[type=\"search\"]');\n+        }, 'Cannot find manage filters search field');\n+        $searchField->setValue($filterName);\n+    }\n+\n+    /**\n+     * Open the filter\n+     *\n+     * @param NodeElement $filter\n+     */\n+    public function openFilter(NodeElement $filter)\n+    {\n+        $element = $this->spin(function () use ($filter) {\n+            return $filter->find('css', 'button');\n+        }, 'Impossible to open filter or maybe its type is not yet implemented');\n+\n+        $element->click();\n+    }\n+\n+    /**\n+     * Get grid filter from label name\n+     *\n+     * @param string $filterName\n+     *\n+     * @throws \\InvalidArgumentException\n+     *\n+     * @return NodeElement\n+     */\n+    public function getFilter($filterName)\n+    {\n+        $filter = $this->spin(function () use ($filterName) {\n+            if (strtolower($filterName) === 'channel') {\n+                $filter = $this->find('css', $this->selectors['Grid toolbar'])->find('css', 'div.filter-item');\n+            } else {\n+                $filter = $this->find('css', sprintf('div.filter-item:contains(\"%s\")', $filterName));\n+            }\n+\n+            return $filter;\n+        }, sprintf('Couldn\\'t find a filter with name \"%s\"', $filterName));\n+\n+        return $filter;\n+    }\n+\n+    /**\n+     * @param string               $filterName The name of the filter\n+     * @param string               $value      The value to filter by\n+     * @param bool|string          $operator   If false, no operator will be selected\n+     * @param DriverInterface|null $driver     Required to filter by multiple choices\n+     *\n+     * @throws \\InvalidArgumentException\n+     */\n+    public function filterBy($filterName, $value, $operator = false, DriverInterface $driver = null)\n+    {\n+        $filter = $this->getFilter($filterName);\n+        $this->openFilter($filter);\n+\n+        if ($elt = $filter->find('css', 'select')) {\n+            if ($elt->getText() === \"between not between more than less than is empty\") {\n+                $this->filterByDate($filter, $value, $operator);\n+            } elseif ($elt->getParent()->find('css', 'button.ui-multiselect')) {\n+                if (!$driver || !$driver instanceof Selenium2Driver) {\n+                    throw new \\InvalidArgumentException('Selenium2Driver is required to filter by a choice filter');\n+                }\n+                $values = explode(',', $value);\n+\n+                foreach ($values as $value) {\n+                    $driver->executeScript(\n+                        sprintf(\n+                            \"$('.ui-multiselect-menu:visible input[title=\\\"%s\\\"]').click().trigger('click');\",\n+                            $value\n+                        )\n+                    );\n+                    sleep(1);\n+                }\n+\n+                // Uncheck the 'All' option\n+                if (!in_array('All', $values)) {\n+                    $driver->executeScript(\n+                        \"var all = $('.ui-multiselect-menu:visible input[title=\\\"All\\\"]');\" .\n+                        \"if (all.length && all.is(':checked')) { all.click().trigger('click'); }\"\n+                    );\n+                }\n+            }\n+        } elseif ($elt = $filter->find('css', 'div.filter-criteria')) {\n+            $results = $this->getFilterAutocomplete();\n+            $select2 = $filter->find('css', '.select2-input');\n+\n+            if (false !== $operator) {\n+                $filter->find('css', 'button.dropdown-toggle')->click();\n+                $filter->find('css', sprintf('[data-value=\"%s\"]', $operator))->click();\n+            }\n+\n+            if (null !== $results && null !== $select2) {\n+                if (in_array($value, ['empty', 'is empty'])) {\n+                    // Allow passing 'empty' as value too (for backwards compability with existing scenarios)\n+                    $filter->find('css', 'button.dropdown-toggle')->click();\n+                    $filterValue = $filter->find('css', '[data-value=\"empty\"]');\n+                    // In reference data, the first click hides the autocompletion of the filter\n+                    // but does not show the filter type list\n+                    if (!$filterValue->isVisible()) {\n+                        $filter->find('css', 'button.dropdown-toggle')->click();\n+                    }\n+                    $filterValue->click();\n+                } else {\n+                    $values = explode(',', $value);\n+                    foreach ($values as $value) {\n+                        $driver->getWebDriverSession()\n+                            ->element('xpath', $select2->getXpath())\n+                            ->postValue(['value' => [$value]]);\n+                        sleep(2);\n+                        $results->find('css', 'li')->click();\n+                        sleep(2);\n+                    }\n+                }\n+            } elseif ($value !== false) {\n+                $elt->fillField('value', $value);\n+            }\n+\n+            $filter->find('css', 'button.filter-update')->click();\n+        } else {\n+            throw new \\InvalidArgumentException(\n+                sprintf('Filtering by \"%s\" is not yet implemented\"', $filterName)\n+            );\n+        }\n+    }\n+\n+    /**\n+     * Make sure a filter is visible\n+     *\n+     * @param string $filterName\n+     *\n+     * @throws \\InvalidArgumentException","path":"features/Pim/Behat/Decorator/GridDecorator/FilterDecorator.php","position":261,"original_position":261,"commit_id":"1de3352c361d5d6e1305b27fe48c49daca053526","original_commit_id":"1de3352c361d5d6e1305b27fe48c49daca053526","user":{"login":"juliensnz","id":1117272,"avatar_url":"https://avatars.githubusercontent.com/u/1117272?v=3","gravatar_id":"","url":"https://api.github.com/users/juliensnz","html_url":"https://github.com/juliensnz","followers_url":"https://api.github.com/users/juliensnz/followers","following_url":"https://api.github.com/users/juliensnz/following{/other_user}","gists_url":"https://api.github.com/users/juliensnz/gists{/gist_id}","starred_url":"https://api.github.com/users/juliensnz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/juliensnz/subscriptions","organizations_url":"https://api.github.com/users/juliensnz/orgs","repos_url":"https://api.github.com/users/juliensnz/repos","events_url":"https://api.github.com/users/juliensnz/events{/privacy}","received_events_url":"https://api.github.com/users/juliensnz/received_events","type":"User","site_admin":false},"body":"you can remove this kind of crap","created_at":"2016-03-29T15:07:59Z","updated_at":"2016-03-29T15:07:59Z","html_url":"https://github.com/akeneo/pim-community-dev/pull/4184#discussion_r57739668","pull_request_url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184","_links":{"self":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/comments/57739668"},"html":{"href":"https://github.com/akeneo/pim-community-dev/pull/4184#discussion_r57739668"},"pull_request":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184"}}},"pull_request":{"url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184","id":63714728,"html_url":"https://github.com/akeneo/pim-community-dev/pull/4184","diff_url":"https://github.com/akeneo/pim-community-dev/pull/4184.diff","patch_url":"https://github.com/akeneo/pim-community-dev/pull/4184.patch","issue_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues/4184","number":4184,"state":"open","locked":false,"title":"[WIP] Behat refactor datagrid","user":{"login":"SamirBoulil","id":1826473,"avatar_url":"https://avatars.githubusercontent.com/u/1826473?v=3","gravatar_id":"","url":"https://api.github.com/users/SamirBoulil","html_url":"https://github.com/SamirBoulil","followers_url":"https://api.github.com/users/SamirBoulil/followers","following_url":"https://api.github.com/users/SamirBoulil/following{/other_user}","gists_url":"https://api.github.com/users/SamirBoulil/gists{/gist_id}","starred_url":"https://api.github.com/users/SamirBoulil/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SamirBoulil/subscriptions","organizations_url":"https://api.github.com/users/SamirBoulil/orgs","repos_url":"https://api.github.com/users/SamirBoulil/repos","events_url":"https://api.github.com/users/SamirBoulil/events{/privacy}","received_events_url":"https://api.github.com/users/SamirBoulil/received_events","type":"User","site_admin":false},"body":"A proposal to refactor the behat datagrid and datagrid context using decorators.\r\n\r\n## Decorator's types\r\n### Definition\r\n\r\nLet's introduce two definitions before starting:\r\n- xyzCapableDecorators are used to decorate pages\r\n- NodeElement decorators decorates low level node element\r\n\r\nCapable decorators are classes which decorate an entire page and which responsibility is to provide access to (also decorated) nodeElement of interest within the page.\r\nIn addition to return this element, it will also decorate the nodeElement with the appropriated decorators for this element.\r\n\r\n### Folder structure:\r\n\r\n- Capable decorators should be placed in `features/Pim/Behat/Decorator/PageDecorator` folder.\r\n- Element decorators are placed within a subfolder of `features/Pim/Behat/Decorator` depending on the context.\r\n- Contexts are placed in `features/Pim/Behat/Context/Domain`:\r\n\r\n## How do I use it ?\r\n\r\nFor instance, the `GridCapableDecorator` is capable to return the nodeElement representing the visible grid of the current page by calling `GridCapableDecorator::getCurrentGrid()`.\r\nThis method will return the nodeElement decorated by some grid compatible decorators like:\r\n- `PaginationDecorator`: sets page size and page number of the grid\r\n- `DataDecorator`: access the rows and columns of the grid\r\n- `ActionDecorator`: provide access to massEdit actions for instance\r\n\r\nIn the context, I can access my GridCapableDecorator and my decorated node element grid using :\r\n```php\r\n$this\r\n   ->getCurrentPage() // Returns a GridCapableDecorator instance\r\n   ->getCurrentGrid() // Returns a nodeElement decorated with PaginationDecorator, DataDecorator...\r\n   ->getPageSize() // Method of the PaginationDecorator\r\n```\r\n\r\n## What's in this PR again ?\r\n\r\n### Grid decorators\r\nThis PR introduces a page decorator to manipulate grids:\r\n- [`Pim\\Behat\\Decorator\\PageDecorator\\GridCapableDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/PageDecorator/GridCapableDecorator.php): Capable of returning a decorated element representing the shown grid\r\n\r\nThis PR introduces the following grid decorators:\r\n- [`Pim\\Behat\\Decorator\\GridDecorator\\DataDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/GridDecorator/DataDecorator.php): access the rows and columns of the grid\r\n- [`Pim\\Behat\\Decorator\\GridDecorator\\ActionDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/GridDecorator/ActionDecorator.php): provide access to massEdit actions for instance\r\n- [`Pim\\Behat\\Decorator\\GridDecorator\\FilterDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/GridDecorator/FilterDecorator.php): to manipulate filters (activate/deactivate as well as changing values)\r\n- [`Pim\\Behat\\Decorator\\GridDecorator\\PaginationDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/GridDecorator/PaginationDecorator.php): to manipulate page size and page number\r\n\r\nBasic usage: [`Pim/Behat/Context/Domain/Enrich/GridFilterContext.php#L30`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Context/Domain/Enrich/GridFilterContext.php#L30)\r\n```php\r\n    /**\r\n     * @param string $filterName\r\n     *\r\n     * @Then /^I show the filter \"([^\"]*)\"$/\r\n     */\r\n    public function iShowTheFilter($filterName)\r\n    {\r\n        $this->getCurrentPage()->getGridFilters()->showFilter($filterName);\r\n    }\r\n```\r\n\r\n### View Decorators\r\n\r\nThis PR introduces a page decorator to manipulate views:\r\n- [`Pim\\Behat\\Decorator\\PageDecorator\\ViewCapableDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/PageDecorator/ViewCapableDecorator.php): Capable of returning a decorated element representing the view selector\r\n\r\nThis PR introduces the following view decorator:\r\n- [`Pim\\Behat\\Decorator\\ViewDecorator\\ViewSelectorDecorator`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/ViewDecorator/ViewSelectorDecorator.php): is capable to create, update, delete, find and apply a view with the view selector of the current page\r\n\r\nBasic usage : [`features/Pim/Behat/Context/Domain/Enrich/ViewContext.php:28`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Context/Domain/Enrich/ViewContext.php#L28)\r\n```php\r\n    /**\r\n     * @param string $viewLabel\r\n     *\r\n     * @When /^I apply the \"([^\"]*)\" view$/\r\n     */\r\n    public function iApplyTheView($viewLabel)\r\n    {\r\n        $viewSelector = $this\r\n               ->getCurrentPage() // Returns a ViewCapableDecorator\r\n              ->getCurrentViewSelector(); // Returns a ViewSelectorDecorator\r\n        $viewSelector->showViewList($viewLabel); // Calls shopViewList function of ViewSelectorDecorator\r\n        $viewSelector->applyView($viewLabel);\r\n        $this->wait();\r\n    }\r\n```\r\n\r\n## Caveats\r\n\r\n### The case of library managed html regions\r\nAccessing node elements that are beyond the scope of a decorated low element can become an hassle. This can especially happen when you try to interact with html elements that are managed by an external library such as Select2.\r\n\r\nSelect2 uses javascript to manage an html list of values. In the dom, the list is appended to the Body tag in order for it to be well displayed and not dependant of the overall style of the page (CSS).\r\n\r\nHow do our low level decorated element supposed to access the select2 list when it is beyond it's scope (Meaning the nodeElement does not contain the list it needs to access) ?\r\n\r\nThe solution that is implemented here is to find the list by searching trough the parents of the node. For instance, to find the select2 list, we use an xpath expression to find the body tag and then within this body tag, find the list we want.\r\n\r\nExample of implementation :\r\n[`features/Pim/Behat/Decorator/GridDecorator/FiltersDecorator.php#L414`](https://github.com/akeneo/pim-community-dev/blob/behat-refactor-datagrid/features/Pim/Behat/Decorator/GridDecorator/FiltersDecorator.php#L414)\r\n```php\r\n    /**\r\n     * Return the values proposed for the opened filter\r\n     *\r\n     * @return \\Pim\\Behat\\Decorator\\ElementDecorator\r\n     */\r\n    protected function getFilterAutocomplete()\r\n    {\r\n        return $this\r\n            ->find('xpath', 'ancestor::body')\r\n            ->find('css', $this->selectors['Filter list autocomplete']);\r\n    }\r\n````\r\n\r\nI'd love to know what you think :) !\r\n\r\n| Q                                 | A\r\n| --------------------------------- | ---\r\n| Added Specs                       | -\r\n| Added Behats                      | Yes\r\n| Changelog updated                 | -\r\n| Review and 2 GTM                  | No\r\n| Micro Demo to the PO (Story only) | -\r\n| Migration script                  | -\r\n| Tech Doc                          | -\r\n\r\n- [ ] Remove wait() calls\r\n- [ ] Clean commits for code review\r\n- [ ] Rebase master","created_at":"2016-03-22T12:54:02Z","updated_at":"2016-03-29T15:07:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3f452f500c046fa5325f323efc9f1e4673b4b497","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184/commits","review_comments_url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184/comments","review_comment_url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/comments{/number}","comments_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues/4184/comments","statuses_url":"https://api.github.com/repos/akeneo/pim-community-dev/statuses/1de3352c361d5d6e1305b27fe48c49daca053526","head":{"label":"akeneo:behat-refactor-datagrid","ref":"behat-refactor-datagrid","sha":"1de3352c361d5d6e1305b27fe48c49daca053526","user":{"login":"akeneo","id":2510186,"avatar_url":"https://avatars.githubusercontent.com/u/2510186?v=3","gravatar_id":"","url":"https://api.github.com/users/akeneo","html_url":"https://github.com/akeneo","followers_url":"https://api.github.com/users/akeneo/followers","following_url":"https://api.github.com/users/akeneo/following{/other_user}","gists_url":"https://api.github.com/users/akeneo/gists{/gist_id}","starred_url":"https://api.github.com/users/akeneo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akeneo/subscriptions","organizations_url":"https://api.github.com/users/akeneo/orgs","repos_url":"https://api.github.com/users/akeneo/repos","events_url":"https://api.github.com/users/akeneo/events{/privacy}","received_events_url":"https://api.github.com/users/akeneo/received_events","type":"Organization","site_admin":false},"repo":{"id":5367323,"name":"pim-community-dev","full_name":"akeneo/pim-community-dev","owner":{"login":"akeneo","id":2510186,"avatar_url":"https://avatars.githubusercontent.com/u/2510186?v=3","gravatar_id":"","url":"https://api.github.com/users/akeneo","html_url":"https://github.com/akeneo","followers_url":"https://api.github.com/users/akeneo/followers","following_url":"https://api.github.com/users/akeneo/following{/other_user}","gists_url":"https://api.github.com/users/akeneo/gists{/gist_id}","starred_url":"https://api.github.com/users/akeneo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akeneo/subscriptions","organizations_url":"https://api.github.com/users/akeneo/orgs","repos_url":"https://api.github.com/users/akeneo/repos","events_url":"https://api.github.com/users/akeneo/events{/privacy}","received_events_url":"https://api.github.com/users/akeneo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/akeneo/pim-community-dev","description":"[Community Development Repository] The open source Product Information Management (PIM)","fork":false,"url":"https://api.github.com/repos/akeneo/pim-community-dev","forks_url":"https://api.github.com/repos/akeneo/pim-community-dev/forks","keys_url":"https://api.github.com/repos/akeneo/pim-community-dev/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akeneo/pim-community-dev/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akeneo/pim-community-dev/teams","hooks_url":"https://api.github.com/repos/akeneo/pim-community-dev/hooks","issue_events_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues/events{/number}","events_url":"https://api.github.com/repos/akeneo/pim-community-dev/events","assignees_url":"https://api.github.com/repos/akeneo/pim-community-dev/assignees{/user}","branches_url":"https://api.github.com/repos/akeneo/pim-community-dev/branches{/branch}","tags_url":"https://api.github.com/repos/akeneo/pim-community-dev/tags","blobs_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/refs{/sha}","trees_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akeneo/pim-community-dev/statuses/{sha}","languages_url":"https://api.github.com/repos/akeneo/pim-community-dev/languages","stargazers_url":"https://api.github.com/repos/akeneo/pim-community-dev/stargazers","contributors_url":"https://api.github.com/repos/akeneo/pim-community-dev/contributors","subscribers_url":"https://api.github.com/repos/akeneo/pim-community-dev/subscribers","subscription_url":"https://api.github.com/repos/akeneo/pim-community-dev/subscription","commits_url":"https://api.github.com/repos/akeneo/pim-community-dev/commits{/sha}","git_commits_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/commits{/sha}","comments_url":"https://api.github.com/repos/akeneo/pim-community-dev/comments{/number}","issue_comment_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues/comments{/number}","contents_url":"https://api.github.com/repos/akeneo/pim-community-dev/contents/{+path}","compare_url":"https://api.github.com/repos/akeneo/pim-community-dev/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akeneo/pim-community-dev/merges","archive_url":"https://api.github.com/repos/akeneo/pim-community-dev/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akeneo/pim-community-dev/downloads","issues_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues{/number}","pulls_url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls{/number}","milestones_url":"https://api.github.com/repos/akeneo/pim-community-dev/milestones{/number}","notifications_url":"https://api.github.com/repos/akeneo/pim-community-dev/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akeneo/pim-community-dev/labels{/name}","releases_url":"https://api.github.com/repos/akeneo/pim-community-dev/releases{/id}","deployments_url":"https://api.github.com/repos/akeneo/pim-community-dev/deployments","created_at":"2012-08-10T09:27:26Z","updated_at":"2016-03-26T19:45:00Z","pushed_at":"2016-03-29T15:05:28Z","git_url":"git://github.com/akeneo/pim-community-dev.git","ssh_url":"git@github.com:akeneo/pim-community-dev.git","clone_url":"https://github.com/akeneo/pim-community-dev.git","svn_url":"https://github.com/akeneo/pim-community-dev","homepage":"http://www.akeneo.com","size":139217,"stargazers_count":297,"watchers_count":297,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":158,"mirror_url":null,"open_issues_count":117,"forks":158,"open_issues":117,"watchers":297,"default_branch":"master"}},"base":{"label":"akeneo:master","ref":"master","sha":"1f264fb18428b3f7bde153dd416ee803cb8d34e6","user":{"login":"akeneo","id":2510186,"avatar_url":"https://avatars.githubusercontent.com/u/2510186?v=3","gravatar_id":"","url":"https://api.github.com/users/akeneo","html_url":"https://github.com/akeneo","followers_url":"https://api.github.com/users/akeneo/followers","following_url":"https://api.github.com/users/akeneo/following{/other_user}","gists_url":"https://api.github.com/users/akeneo/gists{/gist_id}","starred_url":"https://api.github.com/users/akeneo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akeneo/subscriptions","organizations_url":"https://api.github.com/users/akeneo/orgs","repos_url":"https://api.github.com/users/akeneo/repos","events_url":"https://api.github.com/users/akeneo/events{/privacy}","received_events_url":"https://api.github.com/users/akeneo/received_events","type":"Organization","site_admin":false},"repo":{"id":5367323,"name":"pim-community-dev","full_name":"akeneo/pim-community-dev","owner":{"login":"akeneo","id":2510186,"avatar_url":"https://avatars.githubusercontent.com/u/2510186?v=3","gravatar_id":"","url":"https://api.github.com/users/akeneo","html_url":"https://github.com/akeneo","followers_url":"https://api.github.com/users/akeneo/followers","following_url":"https://api.github.com/users/akeneo/following{/other_user}","gists_url":"https://api.github.com/users/akeneo/gists{/gist_id}","starred_url":"https://api.github.com/users/akeneo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akeneo/subscriptions","organizations_url":"https://api.github.com/users/akeneo/orgs","repos_url":"https://api.github.com/users/akeneo/repos","events_url":"https://api.github.com/users/akeneo/events{/privacy}","received_events_url":"https://api.github.com/users/akeneo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/akeneo/pim-community-dev","description":"[Community Development Repository] The open source Product Information Management (PIM)","fork":false,"url":"https://api.github.com/repos/akeneo/pim-community-dev","forks_url":"https://api.github.com/repos/akeneo/pim-community-dev/forks","keys_url":"https://api.github.com/repos/akeneo/pim-community-dev/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akeneo/pim-community-dev/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akeneo/pim-community-dev/teams","hooks_url":"https://api.github.com/repos/akeneo/pim-community-dev/hooks","issue_events_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues/events{/number}","events_url":"https://api.github.com/repos/akeneo/pim-community-dev/events","assignees_url":"https://api.github.com/repos/akeneo/pim-community-dev/assignees{/user}","branches_url":"https://api.github.com/repos/akeneo/pim-community-dev/branches{/branch}","tags_url":"https://api.github.com/repos/akeneo/pim-community-dev/tags","blobs_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/refs{/sha}","trees_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akeneo/pim-community-dev/statuses/{sha}","languages_url":"https://api.github.com/repos/akeneo/pim-community-dev/languages","stargazers_url":"https://api.github.com/repos/akeneo/pim-community-dev/stargazers","contributors_url":"https://api.github.com/repos/akeneo/pim-community-dev/contributors","subscribers_url":"https://api.github.com/repos/akeneo/pim-community-dev/subscribers","subscription_url":"https://api.github.com/repos/akeneo/pim-community-dev/subscription","commits_url":"https://api.github.com/repos/akeneo/pim-community-dev/commits{/sha}","git_commits_url":"https://api.github.com/repos/akeneo/pim-community-dev/git/commits{/sha}","comments_url":"https://api.github.com/repos/akeneo/pim-community-dev/comments{/number}","issue_comment_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues/comments{/number}","contents_url":"https://api.github.com/repos/akeneo/pim-community-dev/contents/{+path}","compare_url":"https://api.github.com/repos/akeneo/pim-community-dev/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akeneo/pim-community-dev/merges","archive_url":"https://api.github.com/repos/akeneo/pim-community-dev/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akeneo/pim-community-dev/downloads","issues_url":"https://api.github.com/repos/akeneo/pim-community-dev/issues{/number}","pulls_url":"https://api.github.com/repos/akeneo/pim-community-dev/pulls{/number}","milestones_url":"https://api.github.com/repos/akeneo/pim-community-dev/milestones{/number}","notifications_url":"https://api.github.com/repos/akeneo/pim-community-dev/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akeneo/pim-community-dev/labels{/name}","releases_url":"https://api.github.com/repos/akeneo/pim-community-dev/releases{/id}","deployments_url":"https://api.github.com/repos/akeneo/pim-community-dev/deployments","created_at":"2012-08-10T09:27:26Z","updated_at":"2016-03-26T19:45:00Z","pushed_at":"2016-03-29T15:05:28Z","git_url":"git://github.com/akeneo/pim-community-dev.git","ssh_url":"git@github.com:akeneo/pim-community-dev.git","clone_url":"https://github.com/akeneo/pim-community-dev.git","svn_url":"https://github.com/akeneo/pim-community-dev","homepage":"http://www.akeneo.com","size":139217,"stargazers_count":297,"watchers_count":297,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":158,"mirror_url":null,"open_issues_count":117,"forks":158,"open_issues":117,"watchers":297,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184"},"html":{"href":"https://github.com/akeneo/pim-community-dev/pull/4184"},"issue":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/issues/4184"},"comments":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/issues/4184/comments"},"review_comments":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184/comments"},"review_comment":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/pulls/4184/commits"},"statuses":{"href":"https://api.github.com/repos/akeneo/pim-community-dev/statuses/1de3352c361d5d6e1305b27fe48c49daca053526"}}}}