{"action":"created","comment":{"url":"https://api.github.com/repos/akretion/voodoo/pulls/comments/68375996","id":68375996,"diff_hunk":"@@ -1,42 +1,318 @@\n #!/usr/bin/env python\n # coding: utf-8\n \n-from inspect import getdoc\n+from plumbum import cli, local\n+from plumbum.cmd import git, docker, grep, sed\n+from plumbum.commands.modifiers import FG, TF, BG\n+from plumbum.cli.terminal import choose\n import logging\n-import sys\n+import os\n+from compose.cli.command import get_project\n+from compose.project import OneOffFilter\n+from compose.parallel import parallel_kill\n+import yaml\n \n-from compose.cli.main import setup_logging, parse_doc_section\n-from compose.project import NoSuchService, ConfigurationError\n-from compose.cli.docopt_command import NoSuchCommand\n-from compose.cli.errors import UserError\n-from docker.errors import APIError\n-from compose.service import BuildError\n-from .voodoo import VoodooCommand\n+compose = local['docker-compose']\n \n-log = logging.getLogger(__name__)\n+\n+DEFAULT_CONF = {\n+    \"shared_eggs\": True,\n+    \"odoo\": \"https://github.com/oca/ocb.git\",\n+    \"template\": \"https://github.com/akretion/voodoo-template.git\",\n+}\n+\n+DEV_DOCKER_COMPOSE_FILENAME = 'dev.docker-compose.yml'\n+\n+ODOO_DEV_DOCKER_COMPOSE_CONFIG = \"\"\"\n+services:\n+  db:\n+    environment:\n+    - POSTGRES_PASSWORD=odoo\n+    - POSTGRES_USER=odoo\n+    - POSTGRES_DB=db\n+    image: akretion/voodoo-postgresql\n+    volumes:\n+    - .db:/var/lib/postgresql/data\n+  mailcatcher:\n+    image: akretion/lightweight-mailcatcher\n+    ports:\n+    - 1280:1080\n+    - 1225:1025\n+  odoo:\n+    environment:\n+    - PYTHONDONTWRITEBYTECODE=True\n+    extends:\n+      file: docker-compose.yml\n+      service: odoo\n+    links:\n+    - db\n+    - mailcatcher\n+    ports:\n+    - 8069:8069\n+    - 8072:8072\n+    volumes:\n+    - .:/workspace\n+version: '2'\n+\"\"\"\n+\n+\n+class Voodoo(cli.Application):\n+    PROGNAME = \"voodoo\"\n+    VERSION = \"1.0\"\n+\n+    dryrun = cli.Flag([\"dry-run\"], help=\"Dry run mode\")\n+\n+    def _run(self, cmd, retcode=FG):\n+        \"\"\"Run a command in a new process and log it\"\"\"\n+        logging.info(cmd)\n+        if (self.dryrun):\n+            print cmd\n+            return True\n+        return cmd & retcode\n+\n+    def _exec(self, cmd, args=[]):\n+        \"\"\"Run a command in the same process and log it\n+        this will replace the current process by the cmd\"\"\"\n+        logging.info([cmd, args])\n+        if (self.dryrun):\n+            print \"os.execvpe (%s, %s, env)\" % (cmd, [cmd] + args)\n+            return True\n+        os.execvpe(cmd, [cmd] + args, local.env)\n+\n+    def _get_home(self):\n+        return os.path.expanduser(\"~\")\n+\n+    def __init__(self, executable):\n+        super(Voodoo, self).__init__(executable)\n+        self.home = self._get_home()\n+        self.shared_folder = os.path.join(self.home, '.voodoo', 'shared')\n+        config_path = os.path.join(self.home, '.voodoo', 'config.yml')\n+\n+        # Read existing configuration\n+        if os.path.isfile(config_path):\n+            config_file = open(config_path, 'r')\n+            config = yaml.safe_load(config_file)\n+        else:\n+            config = {}\n+\n+        # Update configuration with default value and remove dead key\n+        new_config = DEFAULT_CONF.copy()\n+        for key, value in config.items():\n+            if key in DEFAULT_CONF:\n+                new_config[key] = config[key]\n+                # Set Configuration\n+                setattr(self, key, config[key])\n+\n+        # Update config file if needed\n+        if new_config != config:\n+            logging.info(\"The Voodoo Configuration have been updated, \"\n+                         \"please take a look to the new config file\")\n+            if not os.path.exists(self.shared_folder):\n+                os.makedirs(self.shared_folder)\n+            config_file = open(config_path, 'w')\n+            config_file.write(yaml.dump(new_config, default_flow_style=False))\n+            logging.info(\"Update default config file at %s\" % config_path)\n+\n+    @cli.switch(\"--verbose\", help=\"Verbose mode\")\n+    def set_log_level(self):\n+        logging.root.setLevel(logging.INFO)\n+        logging.info('Verbose mode activated')\n+\n+\n+class VoodooSub(cli.Application):\n+\n+    def _exec(self, *args, **kwargs):\n+        self.parent._exec(*args, **kwargs)\n+\n+    def _run(self, *args, **kwargs):\n+        self.parent._run(*args, **kwargs)\n+\n+    def _generate_dev_dockerfile(self):\n+        dc_file = open('docker-compose.yml', 'r')\n+        config = yaml.safe_load(dc_file)\n+        if 'odoo' in config['services']:\n+            template = ODOO_DEV_DOCKER_COMPOSE_CONFIG\n+        else:\n+            raise NotImplemented\n+        config = yaml.safe_load(template)\n+        with open('dev.docker-compose.yml', 'w') as dc_tmp_file:\n+\n+            # share .voodoo folder in voodoo\n+            home = os.path.expanduser(\"~\")\n+            shared = os.path.join(home, '.voodoo', 'shared')\n+            config['services']['odoo']['volumes'].append(\n+                '%s:%s' % (shared, shared))\n+\n+            # inject uid for sharing db folder with host\n+            uid = os.getuid()\n+            for key in ['USERMAP_UID', 'USERMAP_GID']:\n+                config['services']['db']['environment'].append(\n+                    \"%s=%s\" % (key,uid))\n+\n+            dc_tmp_file.write(yaml.dump(config, default_flow_style=False))\n+\n+    def __init__(self, *args, **kwargs):\n+        super(VoodooSub, self).__init__(*args, **kwargs)\n+        if args and args[0] == 'voodoo new':\n+            return\n+        if not os.path.exists(DEV_DOCKER_COMPOSE_FILENAME):\n+            self._generate_dev_dockerfile()\n+        self.compose = compose['-f', DEV_DOCKER_COMPOSE_FILENAME]\n+        self.config_path = DEV_DOCKER_COMPOSE_FILENAME\n+\n+\n+@Voodoo.subcommand(\"run\")\n+class VoodooRun(VoodooSub):\n+\n+    def _get_odoo_cache_path(self):\n+        cache_path = os.path.join(self.parent.shared_folder, 'cached_odoo')\n+        if not os.path.exists(cache_path):\n+            os.makedirs(cache_path)\n+        odoo_cache_path = os.path.join(cache_path, 'odoo')\n+        if not os.path.exists(odoo_cache_path):\n+            logging.info(\n+                \"First run of Voodoo; there is no Odoo repo in %s! \"\n+                \"Will now download Odoo from Github, \"\n+                \"this can take a while...\\n\"\n+                \"If you already have a local Odoo repo (from OCA) \"\n+                \"then you can you can abort the download \"\n+                \"and paste your repo or make a symbolink link in %s\",\n+                odoo_ref_path, odoo_ref_path)\n+            self._run(git[\"clone\", self.parent.odoo, odoo_cache_path])\n+        else:\n+            print \"Update Odoo cache\"\n+            with local.cwd(odoo_cache_path):\n+                self._run(git[\"pull\"])\n+        return odoo_cache_path\n+\n+    def _get_odoo(self, odoo_path):\n+        if not os.path.exists('parts'):\n+            os.makedirs('parts')\n+        odoo_cache_path = self._get_odoo_cache_path()\n+        self._run(git[\"clone\", \"file://%s\" % odoo_cache_path, odoo_path])\n+\n+    def _copy_eggs_directory(self, dest):\n+        self._run(self.compose[\n+            'run', 'odoo', 'cp', '-r', '/opt/voodoo/eggs', dest])\n+\n+    def _init_run(self):\n+        # create db folder if missing\n+        if not os.path.exists('.db'):\n+            os.makedirs('.db')\n+        # Create odoo directory from cache if do not exist\n+        odoo_path = os.path.join('parts', 'odoo')\n+        if not os.path.exists(odoo_path):\n+            self._get_odoo(odoo_path)\n+\n+        # Create shared eggs directory if not exist\n+        home = os.path.expanduser(\"~\")\n+        eggs_path = os.path.join(home, '.voodoo', 'shared', 'eggs')\n+        if not os.path.exists(eggs_path):\n+            self._copy_eggs_directory(eggs_path)\n+\n+        # Init eggs directory : share it or generate a new one\n+        if not os.path.exists('eggs'):\n+            if self.parent.shared_eggs:\n+                os.symlink(eggs_path, 'eggs')\n+            else:\n+                self._copy_eggs_directory(eggs_path)\n+\n+    def main(self, *args):\n+        self._init_run()\n+        # Remove useless dead container before running a new one\n+        self._run(self.compose['rm', '--all', '-f'])\n+        self._exec('docker-compose', [\n+            '-f', DEV_DOCKER_COMPOSE_FILENAME,\n+            'run', '--service-ports',\n+            'odoo', 'bash'])\n+\n+\n+@Voodoo.subcommand(\"open\")\n+class VoodooOpen(VoodooSub):\n+\n+    def main(self, *args):\n+        project = get_project('.', [self.config_path])\n+        container = project.containers(\n+            service_names=['odoo'], one_off=OneOffFilter.include)\n+        if container:\n+            self._run(docker[\"exec\", \"-ti\", container[0].name, \"bash\"])","path":"voodoo/main.py","position":248,"original_position":248,"commit_id":"3b7c49998b81bbe9454c2111cfaa132e4700caee","original_commit_id":"3b7c49998b81bbe9454c2111cfaa132e4700caee","user":{"login":"sebastienbeau","id":1164578,"avatar_url":"https://avatars.githubusercontent.com/u/1164578?v=3","gravatar_id":"","url":"https://api.github.com/users/sebastienbeau","html_url":"https://github.com/sebastienbeau","followers_url":"https://api.github.com/users/sebastienbeau/followers","following_url":"https://api.github.com/users/sebastienbeau/following{/other_user}","gists_url":"https://api.github.com/users/sebastienbeau/gists{/gist_id}","starred_url":"https://api.github.com/users/sebastienbeau/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sebastienbeau/subscriptions","organizations_url":"https://api.github.com/users/sebastienbeau/orgs","repos_url":"https://api.github.com/users/sebastienbeau/repos","events_url":"https://api.github.com/users/sebastienbeau/events{/privacy}","received_events_url":"https://api.github.com/users/sebastienbeau/received_events","type":"User","site_admin":false},"body":"yes better","created_at":"2016-06-24T09:41:27Z","updated_at":"2016-06-24T09:41:27Z","html_url":"https://github.com/akretion/voodoo/pull/44#discussion_r68375996","pull_request_url":"https://api.github.com/repos/akretion/voodoo/pulls/44","_links":{"self":{"href":"https://api.github.com/repos/akretion/voodoo/pulls/comments/68375996"},"html":{"href":"https://github.com/akretion/voodoo/pull/44#discussion_r68375996"},"pull_request":{"href":"https://api.github.com/repos/akretion/voodoo/pulls/44"}}},"pull_request":{"url":"https://api.github.com/repos/akretion/voodoo/pulls/44","id":73496265,"html_url":"https://github.com/akretion/voodoo/pull/44","diff_url":"https://github.com/akretion/voodoo/pull/44.diff","patch_url":"https://github.com/akretion/voodoo/pull/44.patch","issue_url":"https://api.github.com/repos/akretion/voodoo/issues/44","number":44,"state":"open","locked":false,"title":"version 2 of voodoo is coming !","user":{"login":"sebastienbeau","id":1164578,"avatar_url":"https://avatars.githubusercontent.com/u/1164578?v=3","gravatar_id":"","url":"https://api.github.com/users/sebastienbeau","html_url":"https://github.com/sebastienbeau","followers_url":"https://api.github.com/users/sebastienbeau/followers","following_url":"https://api.github.com/users/sebastienbeau/following{/other_user}","gists_url":"https://api.github.com/users/sebastienbeau/gists{/gist_id}","starred_url":"https://api.github.com/users/sebastienbeau/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sebastienbeau/subscriptions","organizations_url":"https://api.github.com/users/sebastienbeau/orgs","repos_url":"https://api.github.com/users/sebastienbeau/repos","events_url":"https://api.github.com/users/sebastienbeau/events{/privacy}","received_events_url":"https://api.github.com/users/sebastienbeau/received_events","type":"User","site_admin":false},"body":"This new version\r\n- use plumbum for the cli\r\n- call docker-compose using the shell (to avoid breaking change)\r\n- clean the dead container before running a new one\r\n- kill correctly the container using voodoo kill\r\n- remove chef stuff\r\n- remove api for adding service (we should simply add code snippet in the documentation)\r\n- simplify the option of the cli\r\n\r\n","created_at":"2016-06-12T13:20:43Z","updated_at":"2016-06-24T09:41:27Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6c6c5ece80db60a3807596a6fcdad28e04e3530f","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/akretion/voodoo/pulls/44/commits","review_comments_url":"https://api.github.com/repos/akretion/voodoo/pulls/44/comments","review_comment_url":"https://api.github.com/repos/akretion/voodoo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/akretion/voodoo/issues/44/comments","statuses_url":"https://api.github.com/repos/akretion/voodoo/statuses/3b7c49998b81bbe9454c2111cfaa132e4700caee","head":{"label":"akretion:v2","ref":"v2","sha":"3b7c49998b81bbe9454c2111cfaa132e4700caee","user":{"login":"akretion","id":1853423,"avatar_url":"https://avatars.githubusercontent.com/u/1853423?v=3","gravatar_id":"","url":"https://api.github.com/users/akretion","html_url":"https://github.com/akretion","followers_url":"https://api.github.com/users/akretion/followers","following_url":"https://api.github.com/users/akretion/following{/other_user}","gists_url":"https://api.github.com/users/akretion/gists{/gist_id}","starred_url":"https://api.github.com/users/akretion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akretion/subscriptions","organizations_url":"https://api.github.com/users/akretion/orgs","repos_url":"https://api.github.com/users/akretion/repos","events_url":"https://api.github.com/users/akretion/events{/privacy}","received_events_url":"https://api.github.com/users/akretion/received_events","type":"Organization","site_admin":false},"repo":{"id":30267463,"name":"voodoo","full_name":"akretion/voodoo","owner":{"login":"akretion","id":1853423,"avatar_url":"https://avatars.githubusercontent.com/u/1853423?v=3","gravatar_id":"","url":"https://api.github.com/users/akretion","html_url":"https://github.com/akretion","followers_url":"https://api.github.com/users/akretion/followers","following_url":"https://api.github.com/users/akretion/following{/other_user}","gists_url":"https://api.github.com/users/akretion/gists{/gist_id}","starred_url":"https://api.github.com/users/akretion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akretion/subscriptions","organizations_url":"https://api.github.com/users/akretion/orgs","repos_url":"https://api.github.com/users/akretion/repos","events_url":"https://api.github.com/users/akretion/events{/privacy}","received_events_url":"https://api.github.com/users/akretion/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/akretion/voodoo","description":"Black magic for your Odoo projects","fork":false,"url":"https://api.github.com/repos/akretion/voodoo","forks_url":"https://api.github.com/repos/akretion/voodoo/forks","keys_url":"https://api.github.com/repos/akretion/voodoo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akretion/voodoo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akretion/voodoo/teams","hooks_url":"https://api.github.com/repos/akretion/voodoo/hooks","issue_events_url":"https://api.github.com/repos/akretion/voodoo/issues/events{/number}","events_url":"https://api.github.com/repos/akretion/voodoo/events","assignees_url":"https://api.github.com/repos/akretion/voodoo/assignees{/user}","branches_url":"https://api.github.com/repos/akretion/voodoo/branches{/branch}","tags_url":"https://api.github.com/repos/akretion/voodoo/tags","blobs_url":"https://api.github.com/repos/akretion/voodoo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akretion/voodoo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akretion/voodoo/git/refs{/sha}","trees_url":"https://api.github.com/repos/akretion/voodoo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akretion/voodoo/statuses/{sha}","languages_url":"https://api.github.com/repos/akretion/voodoo/languages","stargazers_url":"https://api.github.com/repos/akretion/voodoo/stargazers","contributors_url":"https://api.github.com/repos/akretion/voodoo/contributors","subscribers_url":"https://api.github.com/repos/akretion/voodoo/subscribers","subscription_url":"https://api.github.com/repos/akretion/voodoo/subscription","commits_url":"https://api.github.com/repos/akretion/voodoo/commits{/sha}","git_commits_url":"https://api.github.com/repos/akretion/voodoo/git/commits{/sha}","comments_url":"https://api.github.com/repos/akretion/voodoo/comments{/number}","issue_comment_url":"https://api.github.com/repos/akretion/voodoo/issues/comments{/number}","contents_url":"https://api.github.com/repos/akretion/voodoo/contents/{+path}","compare_url":"https://api.github.com/repos/akretion/voodoo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akretion/voodoo/merges","archive_url":"https://api.github.com/repos/akretion/voodoo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akretion/voodoo/downloads","issues_url":"https://api.github.com/repos/akretion/voodoo/issues{/number}","pulls_url":"https://api.github.com/repos/akretion/voodoo/pulls{/number}","milestones_url":"https://api.github.com/repos/akretion/voodoo/milestones{/number}","notifications_url":"https://api.github.com/repos/akretion/voodoo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akretion/voodoo/labels{/name}","releases_url":"https://api.github.com/repos/akretion/voodoo/releases{/id}","deployments_url":"https://api.github.com/repos/akretion/voodoo/deployments","created_at":"2015-02-03T22:13:58Z","updated_at":"2016-04-27T19:03:00Z","pushed_at":"2016-06-24T08:09:10Z","git_url":"git://github.com/akretion/voodoo.git","ssh_url":"git@github.com:akretion/voodoo.git","clone_url":"https://github.com/akretion/voodoo.git","svn_url":"https://github.com/akretion/voodoo","homepage":"https://akretion.github.io/voodoo","size":83,"stargazers_count":9,"watchers_count":9,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":9,"mirror_url":null,"open_issues_count":22,"forks":9,"open_issues":22,"watchers":9,"default_branch":"master"}},"base":{"label":"akretion:master","ref":"master","sha":"899253d97693fb14fc4da76427ed8760974be763","user":{"login":"akretion","id":1853423,"avatar_url":"https://avatars.githubusercontent.com/u/1853423?v=3","gravatar_id":"","url":"https://api.github.com/users/akretion","html_url":"https://github.com/akretion","followers_url":"https://api.github.com/users/akretion/followers","following_url":"https://api.github.com/users/akretion/following{/other_user}","gists_url":"https://api.github.com/users/akretion/gists{/gist_id}","starred_url":"https://api.github.com/users/akretion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akretion/subscriptions","organizations_url":"https://api.github.com/users/akretion/orgs","repos_url":"https://api.github.com/users/akretion/repos","events_url":"https://api.github.com/users/akretion/events{/privacy}","received_events_url":"https://api.github.com/users/akretion/received_events","type":"Organization","site_admin":false},"repo":{"id":30267463,"name":"voodoo","full_name":"akretion/voodoo","owner":{"login":"akretion","id":1853423,"avatar_url":"https://avatars.githubusercontent.com/u/1853423?v=3","gravatar_id":"","url":"https://api.github.com/users/akretion","html_url":"https://github.com/akretion","followers_url":"https://api.github.com/users/akretion/followers","following_url":"https://api.github.com/users/akretion/following{/other_user}","gists_url":"https://api.github.com/users/akretion/gists{/gist_id}","starred_url":"https://api.github.com/users/akretion/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akretion/subscriptions","organizations_url":"https://api.github.com/users/akretion/orgs","repos_url":"https://api.github.com/users/akretion/repos","events_url":"https://api.github.com/users/akretion/events{/privacy}","received_events_url":"https://api.github.com/users/akretion/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/akretion/voodoo","description":"Black magic for your Odoo projects","fork":false,"url":"https://api.github.com/repos/akretion/voodoo","forks_url":"https://api.github.com/repos/akretion/voodoo/forks","keys_url":"https://api.github.com/repos/akretion/voodoo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akretion/voodoo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akretion/voodoo/teams","hooks_url":"https://api.github.com/repos/akretion/voodoo/hooks","issue_events_url":"https://api.github.com/repos/akretion/voodoo/issues/events{/number}","events_url":"https://api.github.com/repos/akretion/voodoo/events","assignees_url":"https://api.github.com/repos/akretion/voodoo/assignees{/user}","branches_url":"https://api.github.com/repos/akretion/voodoo/branches{/branch}","tags_url":"https://api.github.com/repos/akretion/voodoo/tags","blobs_url":"https://api.github.com/repos/akretion/voodoo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akretion/voodoo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akretion/voodoo/git/refs{/sha}","trees_url":"https://api.github.com/repos/akretion/voodoo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akretion/voodoo/statuses/{sha}","languages_url":"https://api.github.com/repos/akretion/voodoo/languages","stargazers_url":"https://api.github.com/repos/akretion/voodoo/stargazers","contributors_url":"https://api.github.com/repos/akretion/voodoo/contributors","subscribers_url":"https://api.github.com/repos/akretion/voodoo/subscribers","subscription_url":"https://api.github.com/repos/akretion/voodoo/subscription","commits_url":"https://api.github.com/repos/akretion/voodoo/commits{/sha}","git_commits_url":"https://api.github.com/repos/akretion/voodoo/git/commits{/sha}","comments_url":"https://api.github.com/repos/akretion/voodoo/comments{/number}","issue_comment_url":"https://api.github.com/repos/akretion/voodoo/issues/comments{/number}","contents_url":"https://api.github.com/repos/akretion/voodoo/contents/{+path}","compare_url":"https://api.github.com/repos/akretion/voodoo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akretion/voodoo/merges","archive_url":"https://api.github.com/repos/akretion/voodoo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akretion/voodoo/downloads","issues_url":"https://api.github.com/repos/akretion/voodoo/issues{/number}","pulls_url":"https://api.github.com/repos/akretion/voodoo/pulls{/number}","milestones_url":"https://api.github.com/repos/akretion/voodoo/milestones{/number}","notifications_url":"https://api.github.com/repos/akretion/voodoo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akretion/voodoo/labels{/name}","releases_url":"https://api.github.com/repos/akretion/voodoo/releases{/id}","deployments_url":"https://api.github.com/repos/akretion/voodoo/deployments","created_at":"2015-02-03T22:13:58Z","updated_at":"2016-04-27T19:03:00Z","pushed_at":"2016-06-24T08:09:10Z","git_url":"git://github.com/akretion/voodoo.git","ssh_url":"git@github.com:akretion/voodoo.git","clone_url":"https://github.com/akretion/voodoo.git","svn_url":"https://github.com/akretion/voodoo","homepage":"https://akretion.github.io/voodoo","size":83,"stargazers_count":9,"watchers_count":9,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":9,"mirror_url":null,"open_issues_count":22,"forks":9,"open_issues":22,"watchers":9,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/akretion/voodoo/pulls/44"},"html":{"href":"https://github.com/akretion/voodoo/pull/44"},"issue":{"href":"https://api.github.com/repos/akretion/voodoo/issues/44"},"comments":{"href":"https://api.github.com/repos/akretion/voodoo/issues/44/comments"},"review_comments":{"href":"https://api.github.com/repos/akretion/voodoo/pulls/44/comments"},"review_comment":{"href":"https://api.github.com/repos/akretion/voodoo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/akretion/voodoo/pulls/44/commits"},"statuses":{"href":"https://api.github.com/repos/akretion/voodoo/statuses/3b7c49998b81bbe9454c2111cfaa132e4700caee"}}}}
{"actor":{"display_login":"sebastienbeau"}}