{"action":"created","comment":{"url":"https://api.github.com/repos/apache/spark/pulls/comments/29111872","id":29111872,"diff_hunk":"@@ -0,0 +1,417 @@\n+#!/usr/bin/env python\n+\n+#\n+# Licensed to the Apache Software Foundation (ASF) under one or more\n+# contributor license agreements.  See the NOTICE file distributed with\n+# this work for additional information regarding copyright ownership.\n+# The ASF licenses this file to You under the Apache License, Version 2.0\n+# (the \"License\"); you may not use this file except in compliance with\n+# the License.  You may obtain a copy of the License at\n+#\n+#    http://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+#\n+\n+import os\n+import re\n+import sys\n+import shutil\n+import subprocess\n+\n+spark_proj_root = \\\n+    os.path.join(os.path.dirname(os.path.realpath(__file__)), \"..\")\n+user_home_dir = os.environ.get(\"HOME\")\n+\n+sbt_maven_profile_args_env = \"SBT_MAVEN_PROFILES_ARGS\"\n+amplab_jenkins_build_tool_env = \"AMPLAB_JENKINS_BUILD_TOOL\"\n+amplab_jenkins_build_tool = os.environ.get(amplab_jenkins_build_tool_env)\n+amplab_jenkins = os.environ.get(\"AMPLAB_JENKINS\")\n+\n+resolving_re = \"^.*[info].*Resolving\"\n+merging_re = \"^.*[warn].*Merging\"\n+including_re = \"^.*[info].*Including\"\n+sbt_output_filter = re.compile(resolving_re + \"|\" + \n+                               merging_re + \"|\" +\n+                               including_re)\n+\n+\n+def get_error_codes(err_code_file):\n+    \"\"\"Function to retrieve all block numbers from the `run-tests-codes.sh`\n+    file to maintain backwards compatibility with the `run-tests-jenkins` \n+    script\"\"\"\n+    \n+    with open(err_code_file, 'r') as f:\n+        err_codes = [e.split()[1].strip().split('=') \n+                     for e in f if e.startswith(\"readonly\")]\n+        return dict(err_codes)\n+\n+\n+def rm_r(path):\n+    \"\"\"Given an arbitrary path properly remove it with the correct python\n+    construct if it exists\n+    - from: http://stackoverflow.com/a/9559881\"\"\"\n+\n+    if os.path.isdir(path):\n+        shutil.rmtree(path)\n+    elif os.path.exists(path):\n+        os.remove(path)\n+\n+\n+def lineno():\n+    \"\"\"Returns the current line number in our program\n+    - from: http://stackoverflow.com/a/3056059\"\"\"\n+\n+    return inspect.currentframe().f_back.f_lineno\n+\n+\n+def run_cmd(cmd):\n+    \"\"\"Given a command as a list of arguments will attempt to execute the\n+    command and, on failure, print an error message\"\"\"\n+\n+    if not isinstance(cmd, list):\n+        cmd = cmd.split()\n+    try:\n+        subprocess.check_output(cmd)\n+    except subprocess.CalledProcessError as e:\n+        print \"[error] running\", e.cmd, \"; received return code\", e.returncode\n+        sys.exit(e.returncode)\n+\n+\n+def set_sbt_maven_profile_args():\n+    \"\"\"Properly sets the SBT environment variable arguments with additional\n+    checks to determine if this is running on an Amplab Jenkins machine\"\"\"\n+\n+    # base environment values for sbt_maven_profile_args_env which will be appended on\n+    sbt_maven_profile_args_base = [\"-Pkinesis-asl\"]\n+\n+    sbt_maven_profile_arg_dict = {\n+        \"hadoop1.0\" : [\"-Dhadoop.version=1.0.4\"],\n+        \"hadoop2.0\" : [\"-Dhadoop.version=2.0.0-mr1-cdh4.1.1\"],\n+        \"hadoop2.2\" : [\"-Pyarn\", \"-Phadoop-2.2\", \"-Dhadoop.version=2.2.0\"],\n+        \"hadoop2.3\" : [\"-Pyarn\", \"-Phadoop-2.3\", \"-Dhadoop.version=2.3.0\"],\n+    }\n+\n+    # set the SBT maven build profile argument environment variable and ensure\n+    # we build against the right version of Hadoop\n+    if os.environ.get(\"AMPLAB_JENKINS_BUILD_PROFILE\"):\n+        os.environ[sbt_maven_profile_args_env] = \\\n+            \" \".join(sbt_maven_profile_arg_dict.get(ajbp, []) \n+                     + sbt_maven_profile_args_base)\n+    else:\n+        os.environ[sbt_maven_profile_args_env] = \\\n+            \" \".join(sbt_maven_profile_arg_dict.get(\"hadoop2.3\", [])\n+                     + sbt_maven_profile_args_base)\n+\n+\n+def is_exe(path):\n+    \"\"\"Check if a given path is an executable file\n+    - from: http://stackoverflow.com/a/377028\"\"\"\n+\n+    return os.path.isfile(path) and os.access(path, os.X_OK)\n+\n+\n+def which(program):\n+    \"\"\"Find and return the given program by its absolute path or 'None'\n+    - from: http://stackoverflow.com/a/377028\"\"\"\n+\n+    fpath, fname = os.path.split(program)\n+\n+    if fpath:\n+        if is_exe(program):\n+            return program\n+    else:\n+        for path in os.environ.get(\"PATH\").split(os.pathsep):\n+            path = path.strip('\"')\n+            exe_file = os.path.join(path, program)\n+            if is_exe(exe_file):\n+                return exe_file\n+    return None\n+\n+\n+def determine_java_executable():\n+    \"\"\"Will return the *best* path possible for a 'java' executable or `None`\"\"\"\n+\n+    java_home = os.environ.get(\"JAVA_HOME\")\n+\n+    # check if there is an executable at $JAVA_HOME/bin/java\n+    java_exe = which(os.path.join(java_home, \"bin/java\"))\n+    # if the java_exe wasn't set, check for a `java` version on the $PATH\n+    return java_exe if java_exe else which(\"java\")\n+\n+\n+def determine_java_version(java_exe):\n+    \"\"\"Given a valid java executable will return its version in tuple format as:\n+    [<major-version>, <minor-version>, <patch-version>, <update-version>]\"\"\"\n+\n+    raw_output = subprocess.check_output([java_exe, \"-version\"], stderr=subprocess.STDOUT)\n+    raw_version_str = raw_output.split('\\n')[0] # eg 'java version \"1.8.0_25\"'\n+    version_str = raw_version_str.split()[-1].strip('\"') # eg '1.8.0_25'\n+    version, update = version_str.split('_') # eg ['1.8.0', '25']\n+\n+    # map over the values and convert them to integers\n+    return map(lambda x: int(x), version.split('.') + [update])\n+\n+\n+def multi_starts_with(orig_str, *prefixes):\n+    \"\"\"Takes a string and an abritrary number of prefixes then checks the\n+    original string for any of the possible prefixes passed in\"\"\"\n+\n+    for s in prefixes:\n+        if orig_str.startswith(s):\n+            return True\n+    return False\n+\n+\n+def determine_test_suite():\n+    \"\"\"This function current acts to determine if SQL tests need to be run in\n+    addition to the core test suite *or* if _only_ SQL tests need to be run\n+    as the git logs show that to be the only thing touched. In the future\n+    this function will act more generically to help further segregate the\n+    test suite runner (hence the function name).\n+    @return a set of unique test names\"\"\"\n+    test_suite = list()\n+\n+    if amplab_jenkins:\n+        run_cmd(['git', 'fetch', 'origin', 'master:master']).wait()\n+\n+        raw_output = subprocess.check_output(['git', 'diff', '--name-only', 'master'])\n+        # remove any empty strings\n+        changed_files = [f for f in raw_output.split('\\n') if f]\n+\n+        # find any sql files\n+        sql_files = [f for f in changed_files\n+                     if multi_starts_with(f, \n+                                          \"sql/\", \n+                                          \"bin/spark-sql\", \n+                                          \"sbin/start-thriftserver.sh\")]\n+\n+        non_sql_files = set(changed_files).difference(set(sql_files))\n+\n+        if non_sql_files:\n+            test_suite.append(\"CORE\")\n+        if sql_files:\n+            print \"[info] Detected changes in SQL. Will run Hive test suite.\"\n+            test_suite.append(\"SQL\")\n+            if not non_sql_files:\n+                print \"[info] Detected no changes except in SQL. Will only run SQL tests.\"\n+        return set(test_suite)\n+    else:\n+        # we aren't in the Amplab environment so merely run all tests\n+        test_suite.append(\"CORE\")\n+        test_suite.append(\"SQL\")\n+        return set(test_suite)\n+\n+\n+def set_title_and_block(title, err_block):\n+    os.environ[\"CURRENT_BLOCK\"] = error_codes[err_block]\n+    line_str = \"\".join(['='] * 72)\n+\n+    print\n+    print line_str\n+    print title\n+    print line_str\n+\n+\n+def run_apache_rat_checks():\n+    set_title_and_block(\"Running Apache RAT checks\", \"BLOCK_RAT\")\n+    run_cmd([\"./dev/check-license\"])\n+\n+\n+def run_scala_style_checks():\n+    set_title_and_block(\"Running Scala style checks\", \"BLOCK_SCALA_STYLE\")\n+    run_cmd([\"./dev/lint-scala\"])\n+\n+\n+def run_python_style_checks():\n+    set_title_and_block(\"Running Python style checks\", \"BLOCK_PYTHON_STYLE\")\n+    run_cmd([\"./dev/lint-python\"])\n+\n+\n+def exec_maven(mvn_args=[]):\n+    \"\"\"Will call Maven in the current directory with the list of mvn_args passed\n+    in and returns the subprocess for any further processing\"\"\"\n+\n+    return subprocess.Popen([\"./build/mvn\"] + mvn_args)\n+\n+\n+def exec_sbt(sbt_args=[]):\n+    \"\"\"Will call SBT in the current directory with the list of mvn_args passed\n+    in and returns the subprocess for any further processing\"\"\"\n+\n+    # NOTE: echo \"q\" is needed because sbt on encountering a build file\n+    # with failure (either resolution or compilation) prompts the user for\n+    # input either q, r, etc to quit or retry. This echo is there to make it\n+    # not block.\n+    echo_proc = subprocess.Popen([\"echo\", \"\\\"q\\n\\\"\"], stdout=subprocess.PIPE)\n+    sbt_proc = subprocess.Popen([\"./build/sbt\"] + sbt_args,\n+                                stdin=echo_proc.stdout,\n+                                stdout=subprocess.PIPE)\n+    echo_proc.wait()\n+    for line in iter(sbt_proc.stdout.readline, ''):\n+        if not sbt_output_filter.match(line):\n+            print line,    \n+    return sbt_proc","path":"dev/run-tests.py","position":258,"original_position":258,"commit_id":"639f1e906e4e5e888f0d5f625033bf0123fda4fb","original_commit_id":"639f1e906e4e5e888f0d5f625033bf0123fda4fb","user":{"login":"nchammas","id":1039369,"avatar_url":"https://avatars.githubusercontent.com/u/1039369?v=3","gravatar_id":"","url":"https://api.github.com/users/nchammas","html_url":"https://github.com/nchammas","followers_url":"https://api.github.com/users/nchammas/followers","following_url":"https://api.github.com/users/nchammas/following{/other_user}","gists_url":"https://api.github.com/users/nchammas/gists{/gist_id}","starred_url":"https://api.github.com/users/nchammas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nchammas/subscriptions","organizations_url":"https://api.github.com/users/nchammas/orgs","repos_url":"https://api.github.com/users/nchammas/repos","events_url":"https://api.github.com/users/nchammas/events{/privacy}","received_events_url":"https://api.github.com/users/nchammas/received_events","type":"User","site_admin":false},"body":"Same here. We should just `wait()` before returning if the purpose of the function is to run something to completion.","created_at":"2015-04-26T17:31:06Z","updated_at":"2015-04-26T17:31:06Z","html_url":"https://github.com/apache/spark/pull/5694#discussion_r29111872","pull_request_url":"https://api.github.com/repos/apache/spark/pulls/5694","_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/comments/29111872"},"html":{"href":"https://github.com/apache/spark/pull/5694#discussion_r29111872"},"pull_request":{"href":"https://api.github.com/repos/apache/spark/pulls/5694"}}},"pull_request":{"url":"https://api.github.com/repos/apache/spark/pulls/5694","id":34088261,"html_url":"https://github.com/apache/spark/pull/5694","diff_url":"https://github.com/apache/spark/pull/5694.diff","patch_url":"https://github.com/apache/spark/pull/5694.patch","issue_url":"https://api.github.com/repos/apache/spark/issues/5694","number":5694,"state":"open","locked":false,"title":"[SPARK-7017][Build][Project Infra]: Refactor dev/run-tests into Python","user":{"login":"brennonyork","id":2230193,"avatar_url":"https://avatars.githubusercontent.com/u/2230193?v=3","gravatar_id":"","url":"https://api.github.com/users/brennonyork","html_url":"https://github.com/brennonyork","followers_url":"https://api.github.com/users/brennonyork/followers","following_url":"https://api.github.com/users/brennonyork/following{/other_user}","gists_url":"https://api.github.com/users/brennonyork/gists{/gist_id}","starred_url":"https://api.github.com/users/brennonyork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brennonyork/subscriptions","organizations_url":"https://api.github.com/users/brennonyork/orgs","repos_url":"https://api.github.com/users/brennonyork/repos","events_url":"https://api.github.com/users/brennonyork/events{/privacy}","received_events_url":"https://api.github.com/users/brennonyork/received_events","type":"User","site_admin":false},"body":"All, this is a first attempt at refactoring `dev/run-tests` into Python. Initially I merely converted all Bash calls over to Python, then moved to a much more modular approach (more functions, moved the calls around, etc.). What is here is the initial culmination and should provide a great base to various downstream issues (e.g. SPARK-7016, modularize / parallelize testing, etc.). Would love comments / suggestions for this initial first step!\r\n\r\n/cc @srowen @pwendell @nchammas","created_at":"2015-04-24T21:35:35Z","updated_at":"2015-04-26T17:31:06Z","closed_at":null,"merged_at":null,"merge_commit_sha":"f841d7fed0dda35c06778efb013e4397ede0075c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/apache/spark/pulls/5694/commits","review_comments_url":"https://api.github.com/repos/apache/spark/pulls/5694/comments","review_comment_url":"https://api.github.com/repos/apache/spark/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apache/spark/issues/5694/comments","statuses_url":"https://api.github.com/repos/apache/spark/statuses/639f1e906e4e5e888f0d5f625033bf0123fda4fb","head":{"label":"brennonyork:SPARK-7017","ref":"SPARK-7017","sha":"639f1e906e4e5e888f0d5f625033bf0123fda4fb","user":{"login":"brennonyork","id":2230193,"avatar_url":"https://avatars.githubusercontent.com/u/2230193?v=3","gravatar_id":"","url":"https://api.github.com/users/brennonyork","html_url":"https://github.com/brennonyork","followers_url":"https://api.github.com/users/brennonyork/followers","following_url":"https://api.github.com/users/brennonyork/following{/other_user}","gists_url":"https://api.github.com/users/brennonyork/gists{/gist_id}","starred_url":"https://api.github.com/users/brennonyork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brennonyork/subscriptions","organizations_url":"https://api.github.com/users/brennonyork/orgs","repos_url":"https://api.github.com/users/brennonyork/repos","events_url":"https://api.github.com/users/brennonyork/events{/privacy}","received_events_url":"https://api.github.com/users/brennonyork/received_events","type":"User","site_admin":false},"repo":{"id":26137014,"name":"spark","full_name":"brennonyork/spark","owner":{"login":"brennonyork","id":2230193,"avatar_url":"https://avatars.githubusercontent.com/u/2230193?v=3","gravatar_id":"","url":"https://api.github.com/users/brennonyork","html_url":"https://github.com/brennonyork","followers_url":"https://api.github.com/users/brennonyork/followers","following_url":"https://api.github.com/users/brennonyork/following{/other_user}","gists_url":"https://api.github.com/users/brennonyork/gists{/gist_id}","starred_url":"https://api.github.com/users/brennonyork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brennonyork/subscriptions","organizations_url":"https://api.github.com/users/brennonyork/orgs","repos_url":"https://api.github.com/users/brennonyork/repos","events_url":"https://api.github.com/users/brennonyork/events{/privacy}","received_events_url":"https://api.github.com/users/brennonyork/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/brennonyork/spark","description":"Mirror of Apache Spark","fork":true,"url":"https://api.github.com/repos/brennonyork/spark","forks_url":"https://api.github.com/repos/brennonyork/spark/forks","keys_url":"https://api.github.com/repos/brennonyork/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/brennonyork/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/brennonyork/spark/teams","hooks_url":"https://api.github.com/repos/brennonyork/spark/hooks","issue_events_url":"https://api.github.com/repos/brennonyork/spark/issues/events{/number}","events_url":"https://api.github.com/repos/brennonyork/spark/events","assignees_url":"https://api.github.com/repos/brennonyork/spark/assignees{/user}","branches_url":"https://api.github.com/repos/brennonyork/spark/branches{/branch}","tags_url":"https://api.github.com/repos/brennonyork/spark/tags","blobs_url":"https://api.github.com/repos/brennonyork/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/brennonyork/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/brennonyork/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/brennonyork/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/brennonyork/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/brennonyork/spark/languages","stargazers_url":"https://api.github.com/repos/brennonyork/spark/stargazers","contributors_url":"https://api.github.com/repos/brennonyork/spark/contributors","subscribers_url":"https://api.github.com/repos/brennonyork/spark/subscribers","subscription_url":"https://api.github.com/repos/brennonyork/spark/subscription","commits_url":"https://api.github.com/repos/brennonyork/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/brennonyork/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/brennonyork/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/brennonyork/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/brennonyork/spark/contents/{+path}","compare_url":"https://api.github.com/repos/brennonyork/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/brennonyork/spark/merges","archive_url":"https://api.github.com/repos/brennonyork/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/brennonyork/spark/downloads","issues_url":"https://api.github.com/repos/brennonyork/spark/issues{/number}","pulls_url":"https://api.github.com/repos/brennonyork/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/brennonyork/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/brennonyork/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/brennonyork/spark/labels{/name}","releases_url":"https://api.github.com/repos/brennonyork/spark/releases{/id}","created_at":"2014-11-03T20:24:12Z","updated_at":"2015-04-20T23:26:12Z","pushed_at":"2015-04-26T01:32:14Z","git_url":"git://github.com/brennonyork/spark.git","ssh_url":"git@github.com:brennonyork/spark.git","clone_url":"https://github.com/brennonyork/spark.git","svn_url":"https://github.com/brennonyork/spark","homepage":null,"size":98918,"stargazers_count":0,"watchers_count":0,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apache:master","ref":"master","sha":"caf0136ec5838cf5bf61f39a5b3474a505a6ae11","user":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"repo":{"id":17165658,"name":"spark","full_name":"apache/spark","owner":{"login":"apache","id":47359,"avatar_url":"https://avatars.githubusercontent.com/u/47359?v=3","gravatar_id":"","url":"https://api.github.com/users/apache","html_url":"https://github.com/apache","followers_url":"https://api.github.com/users/apache/followers","following_url":"https://api.github.com/users/apache/following{/other_user}","gists_url":"https://api.github.com/users/apache/gists{/gist_id}","starred_url":"https://api.github.com/users/apache/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apache/subscriptions","organizations_url":"https://api.github.com/users/apache/orgs","repos_url":"https://api.github.com/users/apache/repos","events_url":"https://api.github.com/users/apache/events{/privacy}","received_events_url":"https://api.github.com/users/apache/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apache/spark","description":"Mirror of Apache Spark","fork":false,"url":"https://api.github.com/repos/apache/spark","forks_url":"https://api.github.com/repos/apache/spark/forks","keys_url":"https://api.github.com/repos/apache/spark/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apache/spark/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apache/spark/teams","hooks_url":"https://api.github.com/repos/apache/spark/hooks","issue_events_url":"https://api.github.com/repos/apache/spark/issues/events{/number}","events_url":"https://api.github.com/repos/apache/spark/events","assignees_url":"https://api.github.com/repos/apache/spark/assignees{/user}","branches_url":"https://api.github.com/repos/apache/spark/branches{/branch}","tags_url":"https://api.github.com/repos/apache/spark/tags","blobs_url":"https://api.github.com/repos/apache/spark/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apache/spark/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apache/spark/git/refs{/sha}","trees_url":"https://api.github.com/repos/apache/spark/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apache/spark/statuses/{sha}","languages_url":"https://api.github.com/repos/apache/spark/languages","stargazers_url":"https://api.github.com/repos/apache/spark/stargazers","contributors_url":"https://api.github.com/repos/apache/spark/contributors","subscribers_url":"https://api.github.com/repos/apache/spark/subscribers","subscription_url":"https://api.github.com/repos/apache/spark/subscription","commits_url":"https://api.github.com/repos/apache/spark/commits{/sha}","git_commits_url":"https://api.github.com/repos/apache/spark/git/commits{/sha}","comments_url":"https://api.github.com/repos/apache/spark/comments{/number}","issue_comment_url":"https://api.github.com/repos/apache/spark/issues/comments{/number}","contents_url":"https://api.github.com/repos/apache/spark/contents/{+path}","compare_url":"https://api.github.com/repos/apache/spark/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apache/spark/merges","archive_url":"https://api.github.com/repos/apache/spark/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apache/spark/downloads","issues_url":"https://api.github.com/repos/apache/spark/issues{/number}","pulls_url":"https://api.github.com/repos/apache/spark/pulls{/number}","milestones_url":"https://api.github.com/repos/apache/spark/milestones{/number}","notifications_url":"https://api.github.com/repos/apache/spark/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apache/spark/labels{/name}","releases_url":"https://api.github.com/repos/apache/spark/releases{/id}","created_at":"2014-02-25T08:00:08Z","updated_at":"2015-04-26T15:51:01Z","pushed_at":"2015-04-26T16:54:59Z","git_url":"git://github.com/apache/spark.git","ssh_url":"git@github.com:apache/spark.git","clone_url":"https://github.com/apache/spark.git","svn_url":"https://github.com/apache/spark","homepage":null,"size":1564590,"stargazers_count":3752,"watchers_count":3752,"language":"Scala","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":3262,"mirror_url":"git://git.apache.org/spark.git","open_issues_count":309,"forks":3262,"open_issues":309,"watchers":3752,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apache/spark/pulls/5694"},"html":{"href":"https://github.com/apache/spark/pull/5694"},"issue":{"href":"https://api.github.com/repos/apache/spark/issues/5694"},"comments":{"href":"https://api.github.com/repos/apache/spark/issues/5694/comments"},"review_comments":{"href":"https://api.github.com/repos/apache/spark/pulls/5694/comments"},"review_comment":{"href":"https://api.github.com/repos/apache/spark/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apache/spark/pulls/5694/commits"},"statuses":{"href":"https://api.github.com/repos/apache/spark/statuses/639f1e906e4e5e888f0d5f625033bf0123fda4fb"}}}}