{"action":"created","comment":{"url":"https://api.github.com/repos/golemfactory/golem/pulls/comments/193444788","pull_request_review_id":126418232,"id":193444788,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDE5MzQ0NDc4OA==","diff_hunk":"@@ -1,83 +1,158 @@\n import logging\r\n+import os\r\n+import re\r\n+from configparser import ConfigParser, ParsingError\r\n+from importlib import import_module\r\n+from shutil import copy\r\n+from typing import Dict, List, Optional\r\n+\r\n+from golem.clientconfigdescriptor import ClientConfigDescriptor\r\n+from golem.core.common import get_golem_path\r\n from golem.environments.environmentsconfig import EnvironmentsConfig\r\n-from .environment import Environment, SupportStatus, UnsupportReason\r\n+from .environment import Environment\r\n \r\n logger = logging.getLogger(__name__)\r\n \r\n+REGISTERED_ENVS_FILE = \"registered_envs.ini\"\r\n+REGISTERED_ENVS_TEST_FILE = \"registered_envs_test.ini\"\r\n+\r\n \r\n class EnvironmentsManager(object):\r\n-    \"\"\" Manage known environments. Allow user to choose accepted environment, keep track of supported environments \"\"\"\r\n+    \"\"\" Manage known environments. Allow user to choose accepted environment,\r\n+    keep track of supported environments \"\"\"\r\n \r\n     def __init__(self):\r\n-        self.support_statuses = {}\r\n-        self.environments = set()\r\n+        self.environments_for_tasks: Dict[str, List[Environment]] = {}\r\n         self.env_config = None\r\n \r\n+    def load_all_envs(self, datadir, mainnet):\r\n+        self._load_registered_envs(datadir, REGISTERED_ENVS_FILE)\r\n+        if not mainnet:\r\n+            self._load_registered_envs(datadir, REGISTERED_ENVS_TEST_FILE)\r\n+\r\n+    # pylint: disable=too-many-locals\r\n+    def _load_registered_envs(self, datadir, config_filename):\r\n+        \"\"\"\r\n+        Initializes registered environemnts. Looks for environments in\r\n+        datadir/config_filename. If this file does not exist, this method\r\n+        copies in new config_filename with default values.\r\n+        If datadir is None, just reads the default config in.\r\n+        \"\"\"\r\n+        def parse_args(args: str) -> Dict[str, str]:\r\n+            argslist = (arg.split('=') for arg in args.split(',')\r\n+                        if re.match(r'\\w+=\\w+', arg))\r\n+            return {arg[0]: arg[1] for arg in argslist}\r\n+\r\n+        config_path = os.path.join(get_golem_path(), 'apps', config_filename)\r\n+        if datadir:\r\n+            local_config_path = os.path.join(datadir, config_filename)\r\n+            if not os.path.exists(local_config_path):\r\n+                copy(config_path, local_config_path)\r\n+            config_path = local_config_path\r\n+\r\n+        try:\r\n+            parser = ConfigParser()\r\n+            parser.read_file(open(config_path))\r\n+            for task_type in parser.sections():\r\n+                envs = parser.get(task_type, 'envs').split(';')\r\n+                for env_entry in envs:\r\n+                    # each env entry is formed\r\n+                    # pa.ck.age.cls_name(opt1=val1,opt2=val2...)\r\n+                    m = re.match(r'([a-zA-Z.]+)\\((.*)\\)', env_entry.strip())\r\n+                    if not m:\r\n+                        raise ValueError(\r\n+                            f'In config file {config_path}:'\r\n+                            f' entry {env_entry} cannot be parsed.')\r\n+                    env_cls, args = m.groups()\r\n+\r\n+                    package, name = env_cls.rsplit('.', 1)\r\n+                    module = import_module(package)\r\n+                    env = getattr(module, name)\r\n+\r\n+                    kwargs = parse_args(args)\r\n+                    self.add_environment(task_type, env.create(**kwargs))\r\n+        except (ParsingError, ValueError):\r\n+            logger.error('Failed to parse config file %s', config_filename)\r\n+            # golem will not be working correctly without environments\r\n+            raise\r\n+        except (ModuleNotFoundError, AttributeError):\r\n+            logger.error(\r\n+                'Failed to import environments specified in config file %s',\r\n+                config_filename)\r\n+            raise\r\n+\r\n+\r\n     def load_config(self, datadir):\r\n         \"\"\" Load acceptance of environments from the config file\r\n         :param datadir:\r\n         \"\"\"\r\n         self.env_config = EnvironmentsConfig.load_config(\r\n             self.get_environments_to_config(), datadir)\r\n         config_entries = self.env_config.get_config_entries()\r\n-        for env in self.environments:\r\n-            getter_for_env = getattr(config_entries, \"get_\" + env.get_id())\r\n-            env.accept_tasks = getter_for_env()\r\n+        for env in self.get_environments():\r\n+            getter_name = \"get_\" + env.get_id()\r\n+            if hasattr(config_entries, getter_name):\r\n+                getter_for_env = getattr(config_entries, getter_name)\r\n+                env.accept_tasks = getter_for_env()\r\n \r\n-    def add_environment(self, environment):\r\n-        \"\"\" Add new environment to the manager. Check if environment is supported.\r\n-        :param Environment environment:\r\n+    def change_config(self, config: ClientConfigDescriptor):\r\n+        \"\"\" Notifies all environments about new client config. It's up to\r\n+        each environment to dedice what to do with that information.\r\n+        :param config:\r\n         \"\"\"\r\n-        self.environments.add(environment)\r\n-        supported = environment.check_support()\r\n-        logger.info(\"Adding environment {} supported={}\"\r\n-                    .format(environment.get_id(), supported))\r\n-        self.support_statuses[environment.get_id()] = supported\r\n-\r\n-    def get_support_status(self, env_id) -> SupportStatus:\r\n-        \"\"\" Return information if given environment are supported.\r\n-            Uses information from supported environments,\r\n-            doesn't check the environment again.\r\n-        :param str env_id:\r\n-        :return SupportStatus:\r\n-        \"\"\"\r\n-        return self.support_statuses.get(env_id, SupportStatus.err(\r\n-            {UnsupportReason.ENVIRONMENT_MISSING: env_id}))\r\n+        for env in self.get_environments():\r\n+            env.change_config(config)\r\n \r\n-    def accept_tasks(self, env_id):\r\n-        \"\"\"Return information whether tasks from given environment are accepted.\r\n-        :param str env_id:\r\n-        :return bool:\r\n+    def add_environment(self, task_type: str, environment: Environment):\r\n+        \"\"\" Add new environment to the manager. Check if environment\r\n+        is supported.\r\n+        :param str task_type: task type for which this environment is added.\r\n+        :param Environment environment:\r\n         \"\"\"\r\n-        for env in self.environments:\r\n-            if env.get_id() == env_id:\r\n-                return env.is_accepted()\r\n+        self._prepare_type_for_environment(task_type)\r\n+        self.environments_for_tasks[task_type].append(environment)\r\n+        supported = environment.check_support()\r\n+        logger.info(\"Adding environment %s for type %s; supported=%s\",\r\n+                    environment.get_id(), task_type, supported)\r\n \r\n     def get_environments(self):\r\n         \"\"\" Return all known environments\r\n         :return set:\r\n         \"\"\"\r\n-        return self.environments\r\n+        return set().union(*self.environments_for_tasks.values())\r\n+\r\n+    def get_environment_for_task(self, task_type, requirements) \\\r\n+            -> Optional[Environment]:\r\n+        \"\"\" Return environment suitable for given task_type and requirements.\r\n+        Takes into account environments 'accept_tasks' and support\r\n+        status, returns first Environment for given task_type that is enabled\r\n+        and satisfies all the requirements\r\n+        :param task_type: type of task\r\n+        :param requirements: list of requirements which must be satisfied\r\n+        :return: environment or None\r\n+        \"\"\"\r\n+        envs = (e for e in self.environments_for_tasks.get(task_type, [])\r","path":"golem/environments/environmentsmanager.py","position":167,"original_position":167,"commit_id":"ed3ed18a71aaaab1c72eca5d8195871d3305f0e9","original_commit_id":"ed3ed18a71aaaab1c72eca5d8195871d3305f0e9","user":{"login":"RDProjekt","id":8257240,"node_id":"MDQ6VXNlcjgyNTcyNDA=","avatar_url":"https://avatars2.githubusercontent.com/u/8257240?v=4","gravatar_id":"","url":"https://api.github.com/users/RDProjekt","html_url":"https://github.com/RDProjekt","followers_url":"https://api.github.com/users/RDProjekt/followers","following_url":"https://api.github.com/users/RDProjekt/following{/other_user}","gists_url":"https://api.github.com/users/RDProjekt/gists{/gist_id}","starred_url":"https://api.github.com/users/RDProjekt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RDProjekt/subscriptions","organizations_url":"https://api.github.com/users/RDProjekt/orgs","repos_url":"https://api.github.com/users/RDProjekt/repos","events_url":"https://api.github.com/users/RDProjekt/events{/privacy}","received_events_url":"https://api.github.com/users/RDProjekt/received_events","type":"User","site_admin":false},"body":"this is get() on a map, so empty list is the default value if no environments were reqistered for this type. Requirements are checked 3 lines below.","created_at":"2018-06-06T15:04:30Z","updated_at":"2018-06-06T15:04:31Z","html_url":"https://github.com/golemfactory/golem/pull/2848#discussion_r193444788","pull_request_url":"https://api.github.com/repos/golemfactory/golem/pulls/2848","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/golemfactory/golem/pulls/comments/193444788"},"html":{"href":"https://github.com/golemfactory/golem/pull/2848#discussion_r193444788"},"pull_request":{"href":"https://api.github.com/repos/golemfactory/golem/pulls/2848"}},"in_reply_to_id":193424560},"pull_request":{"url":"https://api.github.com/repos/golemfactory/golem/pulls/2848","id":192641612,"node_id":"MDExOlB1bGxSZXF1ZXN0MTkyNjQxNjEy","html_url":"https://github.com/golemfactory/golem/pull/2848","diff_url":"https://github.com/golemfactory/golem/pull/2848.diff","patch_url":"https://github.com/golemfactory/golem/pull/2848.patch","issue_url":"https://api.github.com/repos/golemfactory/golem/issues/2848","number":2848,"state":"open","locked":false,"title":"PoC firejail","user":{"login":"RDProjekt","id":8257240,"node_id":"MDQ6VXNlcjgyNTcyNDA=","avatar_url":"https://avatars2.githubusercontent.com/u/8257240?v=4","gravatar_id":"","url":"https://api.github.com/users/RDProjekt","html_url":"https://github.com/RDProjekt","followers_url":"https://api.github.com/users/RDProjekt/followers","following_url":"https://api.github.com/users/RDProjekt/following{/other_user}","gists_url":"https://api.github.com/users/RDProjekt/gists{/gist_id}","starred_url":"https://api.github.com/users/RDProjekt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RDProjekt/subscriptions","organizations_url":"https://api.github.com/users/RDProjekt/orgs","repos_url":"https://api.github.com/users/RDProjekt/repos","events_url":"https://api.github.com/users/RDProjekt/events{/privacy}","received_events_url":"https://api.github.com/users/RDProjekt/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-06-05T09:21:34Z","updated_at":"2018-06-06T15:04:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"d501c77481cf3cb3e6d234c9ef2c5166e6c599b8","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/golemfactory/golem/pulls/2848/commits","review_comments_url":"https://api.github.com/repos/golemfactory/golem/pulls/2848/comments","review_comment_url":"https://api.github.com/repos/golemfactory/golem/pulls/comments{/number}","comments_url":"https://api.github.com/repos/golemfactory/golem/issues/2848/comments","statuses_url":"https://api.github.com/repos/golemfactory/golem/statuses/ed3ed18a71aaaab1c72eca5d8195871d3305f0e9","head":{"label":"RDProjekt:rdp/PoC_firejail","ref":"rdp/PoC_firejail","sha":"ed3ed18a71aaaab1c72eca5d8195871d3305f0e9","user":{"login":"RDProjekt","id":8257240,"node_id":"MDQ6VXNlcjgyNTcyNDA=","avatar_url":"https://avatars2.githubusercontent.com/u/8257240?v=4","gravatar_id":"","url":"https://api.github.com/users/RDProjekt","html_url":"https://github.com/RDProjekt","followers_url":"https://api.github.com/users/RDProjekt/followers","following_url":"https://api.github.com/users/RDProjekt/following{/other_user}","gists_url":"https://api.github.com/users/RDProjekt/gists{/gist_id}","starred_url":"https://api.github.com/users/RDProjekt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RDProjekt/subscriptions","organizations_url":"https://api.github.com/users/RDProjekt/orgs","repos_url":"https://api.github.com/users/RDProjekt/repos","events_url":"https://api.github.com/users/RDProjekt/events{/privacy}","received_events_url":"https://api.github.com/users/RDProjekt/received_events","type":"User","site_admin":false},"repo":{"id":108429519,"node_id":"MDEwOlJlcG9zaXRvcnkxMDg0Mjk1MTk=","name":"golem","full_name":"RDProjekt/golem","owner":{"login":"RDProjekt","id":8257240,"node_id":"MDQ6VXNlcjgyNTcyNDA=","avatar_url":"https://avatars2.githubusercontent.com/u/8257240?v=4","gravatar_id":"","url":"https://api.github.com/users/RDProjekt","html_url":"https://github.com/RDProjekt","followers_url":"https://api.github.com/users/RDProjekt/followers","following_url":"https://api.github.com/users/RDProjekt/following{/other_user}","gists_url":"https://api.github.com/users/RDProjekt/gists{/gist_id}","starred_url":"https://api.github.com/users/RDProjekt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RDProjekt/subscriptions","organizations_url":"https://api.github.com/users/RDProjekt/orgs","repos_url":"https://api.github.com/users/RDProjekt/repos","events_url":"https://api.github.com/users/RDProjekt/events{/privacy}","received_events_url":"https://api.github.com/users/RDProjekt/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/RDProjekt/golem","description":"Golem is creating a global market for computing power.","fork":true,"url":"https://api.github.com/repos/RDProjekt/golem","forks_url":"https://api.github.com/repos/RDProjekt/golem/forks","keys_url":"https://api.github.com/repos/RDProjekt/golem/keys{/key_id}","collaborators_url":"https://api.github.com/repos/RDProjekt/golem/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/RDProjekt/golem/teams","hooks_url":"https://api.github.com/repos/RDProjekt/golem/hooks","issue_events_url":"https://api.github.com/repos/RDProjekt/golem/issues/events{/number}","events_url":"https://api.github.com/repos/RDProjekt/golem/events","assignees_url":"https://api.github.com/repos/RDProjekt/golem/assignees{/user}","branches_url":"https://api.github.com/repos/RDProjekt/golem/branches{/branch}","tags_url":"https://api.github.com/repos/RDProjekt/golem/tags","blobs_url":"https://api.github.com/repos/RDProjekt/golem/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/RDProjekt/golem/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/RDProjekt/golem/git/refs{/sha}","trees_url":"https://api.github.com/repos/RDProjekt/golem/git/trees{/sha}","statuses_url":"https://api.github.com/repos/RDProjekt/golem/statuses/{sha}","languages_url":"https://api.github.com/repos/RDProjekt/golem/languages","stargazers_url":"https://api.github.com/repos/RDProjekt/golem/stargazers","contributors_url":"https://api.github.com/repos/RDProjekt/golem/contributors","subscribers_url":"https://api.github.com/repos/RDProjekt/golem/subscribers","subscription_url":"https://api.github.com/repos/RDProjekt/golem/subscription","commits_url":"https://api.github.com/repos/RDProjekt/golem/commits{/sha}","git_commits_url":"https://api.github.com/repos/RDProjekt/golem/git/commits{/sha}","comments_url":"https://api.github.com/repos/RDProjekt/golem/comments{/number}","issue_comment_url":"https://api.github.com/repos/RDProjekt/golem/issues/comments{/number}","contents_url":"https://api.github.com/repos/RDProjekt/golem/contents/{+path}","compare_url":"https://api.github.com/repos/RDProjekt/golem/compare/{base}...{head}","merges_url":"https://api.github.com/repos/RDProjekt/golem/merges","archive_url":"https://api.github.com/repos/RDProjekt/golem/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/RDProjekt/golem/downloads","issues_url":"https://api.github.com/repos/RDProjekt/golem/issues{/number}","pulls_url":"https://api.github.com/repos/RDProjekt/golem/pulls{/number}","milestones_url":"https://api.github.com/repos/RDProjekt/golem/milestones{/number}","notifications_url":"https://api.github.com/repos/RDProjekt/golem/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/RDProjekt/golem/labels{/name}","releases_url":"https://api.github.com/repos/RDProjekt/golem/releases{/id}","deployments_url":"https://api.github.com/repos/RDProjekt/golem/deployments","created_at":"2017-10-26T15:21:49Z","updated_at":"2017-10-26T15:21:52Z","pushed_at":"2018-06-06T10:40:00Z","git_url":"git://github.com/RDProjekt/golem.git","ssh_url":"git@github.com:RDProjekt/golem.git","clone_url":"https://github.com/RDProjekt/golem.git","svn_url":"https://github.com/RDProjekt/golem","homepage":"https://golem.network","size":81184,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"golemfactory:develop_9_05_2018","ref":"develop_9_05_2018","sha":"5cbe19462b66ed947d04e30dd6a63b9d63723b2c","user":{"login":"golemfactory","id":23193179,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIzMTkzMTc5","avatar_url":"https://avatars1.githubusercontent.com/u/23193179?v=4","gravatar_id":"","url":"https://api.github.com/users/golemfactory","html_url":"https://github.com/golemfactory","followers_url":"https://api.github.com/users/golemfactory/followers","following_url":"https://api.github.com/users/golemfactory/following{/other_user}","gists_url":"https://api.github.com/users/golemfactory/gists{/gist_id}","starred_url":"https://api.github.com/users/golemfactory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/golemfactory/subscriptions","organizations_url":"https://api.github.com/users/golemfactory/orgs","repos_url":"https://api.github.com/users/golemfactory/repos","events_url":"https://api.github.com/users/golemfactory/events{/privacy}","received_events_url":"https://api.github.com/users/golemfactory/received_events","type":"Organization","site_admin":false},"repo":{"id":46433937,"node_id":"MDEwOlJlcG9zaXRvcnk0NjQzMzkzNw==","name":"golem","full_name":"golemfactory/golem","owner":{"login":"golemfactory","id":23193179,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIzMTkzMTc5","avatar_url":"https://avatars1.githubusercontent.com/u/23193179?v=4","gravatar_id":"","url":"https://api.github.com/users/golemfactory","html_url":"https://github.com/golemfactory","followers_url":"https://api.github.com/users/golemfactory/followers","following_url":"https://api.github.com/users/golemfactory/following{/other_user}","gists_url":"https://api.github.com/users/golemfactory/gists{/gist_id}","starred_url":"https://api.github.com/users/golemfactory/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/golemfactory/subscriptions","organizations_url":"https://api.github.com/users/golemfactory/orgs","repos_url":"https://api.github.com/users/golemfactory/repos","events_url":"https://api.github.com/users/golemfactory/events{/privacy}","received_events_url":"https://api.github.com/users/golemfactory/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/golemfactory/golem","description":"Golem is creating a global market for computing power.","fork":false,"url":"https://api.github.com/repos/golemfactory/golem","forks_url":"https://api.github.com/repos/golemfactory/golem/forks","keys_url":"https://api.github.com/repos/golemfactory/golem/keys{/key_id}","collaborators_url":"https://api.github.com/repos/golemfactory/golem/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/golemfactory/golem/teams","hooks_url":"https://api.github.com/repos/golemfactory/golem/hooks","issue_events_url":"https://api.github.com/repos/golemfactory/golem/issues/events{/number}","events_url":"https://api.github.com/repos/golemfactory/golem/events","assignees_url":"https://api.github.com/repos/golemfactory/golem/assignees{/user}","branches_url":"https://api.github.com/repos/golemfactory/golem/branches{/branch}","tags_url":"https://api.github.com/repos/golemfactory/golem/tags","blobs_url":"https://api.github.com/repos/golemfactory/golem/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/golemfactory/golem/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/golemfactory/golem/git/refs{/sha}","trees_url":"https://api.github.com/repos/golemfactory/golem/git/trees{/sha}","statuses_url":"https://api.github.com/repos/golemfactory/golem/statuses/{sha}","languages_url":"https://api.github.com/repos/golemfactory/golem/languages","stargazers_url":"https://api.github.com/repos/golemfactory/golem/stargazers","contributors_url":"https://api.github.com/repos/golemfactory/golem/contributors","subscribers_url":"https://api.github.com/repos/golemfactory/golem/subscribers","subscription_url":"https://api.github.com/repos/golemfactory/golem/subscription","commits_url":"https://api.github.com/repos/golemfactory/golem/commits{/sha}","git_commits_url":"https://api.github.com/repos/golemfactory/golem/git/commits{/sha}","comments_url":"https://api.github.com/repos/golemfactory/golem/comments{/number}","issue_comment_url":"https://api.github.com/repos/golemfactory/golem/issues/comments{/number}","contents_url":"https://api.github.com/repos/golemfactory/golem/contents/{+path}","compare_url":"https://api.github.com/repos/golemfactory/golem/compare/{base}...{head}","merges_url":"https://api.github.com/repos/golemfactory/golem/merges","archive_url":"https://api.github.com/repos/golemfactory/golem/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/golemfactory/golem/downloads","issues_url":"https://api.github.com/repos/golemfactory/golem/issues{/number}","pulls_url":"https://api.github.com/repos/golemfactory/golem/pulls{/number}","milestones_url":"https://api.github.com/repos/golemfactory/golem/milestones{/number}","notifications_url":"https://api.github.com/repos/golemfactory/golem/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/golemfactory/golem/labels{/name}","releases_url":"https://api.github.com/repos/golemfactory/golem/releases{/id}","deployments_url":"https://api.github.com/repos/golemfactory/golem/deployments","created_at":"2015-11-18T17:02:35Z","updated_at":"2018-06-06T04:06:52Z","pushed_at":"2018-06-06T14:50:38Z","git_url":"git://github.com/golemfactory/golem.git","ssh_url":"git@github.com:golemfactory/golem.git","clone_url":"https://github.com/golemfactory/golem.git","svn_url":"https://github.com/golemfactory/golem","homepage":"https://golem.network","size":91118,"stargazers_count":2501,"watchers_count":2501,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":257,"mirror_url":null,"archived":false,"open_issues_count":291,"license":{"key":"gpl-3.0","name":"GNU General Public License v3.0","spdx_id":"GPL-3.0","url":"https://api.github.com/licenses/gpl-3.0","node_id":"MDc6TGljZW5zZTk="},"forks":257,"open_issues":291,"watchers":2501,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/golemfactory/golem/pulls/2848"},"html":{"href":"https://github.com/golemfactory/golem/pull/2848"},"issue":{"href":"https://api.github.com/repos/golemfactory/golem/issues/2848"},"comments":{"href":"https://api.github.com/repos/golemfactory/golem/issues/2848/comments"},"review_comments":{"href":"https://api.github.com/repos/golemfactory/golem/pulls/2848/comments"},"review_comment":{"href":"https://api.github.com/repos/golemfactory/golem/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/golemfactory/golem/pulls/2848/commits"},"statuses":{"href":"https://api.github.com/repos/golemfactory/golem/statuses/ed3ed18a71aaaab1c72eca5d8195871d3305f0e9"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"RDProjekt"}}