Bug 1374290 - Import Pull Requests from Test262. r=shu
authorLeo Balter <leonardo.balter@gmail.com>
Tue, 01 Aug 2017 16:19:50 -0700
changeset 421890 b5e11a443f1b8cd884bcc9694722ee13af83572d
parent 421889 fa83b1463e2b061ed6ca9a92faf61776f1376df7
child 421891 7fc035bd5371bd8d9f1910dde7a178321d4a51ed
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshu
bugs1374290
milestone56.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1374290 - Import Pull Requests from Test262. r=shu
js/src/tests/test262-update.py
--- a/js/src/tests/test262-update.py
+++ b/js/src/tests/test262-update.py
@@ -324,17 +324,20 @@ def process_test262(test262Dir, test262O
     # Intl.PluralRules isn't yet enabled by default.
     localIncludesMap[os.path.join("intl402", "PluralRules")] = ["test262-intl-extras.js"]
 
     # Process all test directories recursively.
     for (dirPath, dirNames, fileNames) in os.walk(testDir):
         relPath = os.path.relpath(dirPath, testDir)
         if relPath == ".":
             continue
-        os.makedirs(os.path.join(test262OutDir, relPath))
+
+        # Skip creating a "prs" directory if it already exists
+        if relPath != "prs" or not os.path.exists(os.path.join(test262OutDir, relPath)):
+            os.makedirs(os.path.join(test262OutDir, relPath))
 
         includeSet = set()
         includesMap[relPath] = includeSet
 
         if relPath in explicitIncludes:
             includeSet.update(explicitIncludes[relPath])
 
         # Convert each test file.
@@ -355,73 +358,147 @@ def process_test262(test262Dir, test262O
             for (newFileName, newSource) in convertTestFile(test262parser, testSource, testName, includeSet, strictTests):
                 writeTestFile(test262OutDir, newFileName, newSource)
 
         # Add shell.js and browers.js files for the current directory.
         writeShellAndBrowserFiles(test262OutDir, harnessDir, includesMap, localIncludesMap, relPath)
 
 def update_test262(args):
     import subprocess
+    import requests
+    import json
 
     url = args.url
     branch = args.branch
     revision = args.revision
     outDir = args.out
+    prNumber = args.pull
+
     if not os.path.isabs(outDir):
         outDir = os.path.join(os.getcwd(), outDir)
+
     strictTests = args.strict
-    localTestsOutDir = os.path.join(outDir, "local");
+    localTestsOutDir = os.path.join(outDir, "local")
+    prsTestsOutDir = os.path.join(outDir, "prs")
 
     # Download the requested branch in a temporary directory.
     with TemporaryDirectory() as inDir:
+        restoreLocalTestsDir = False
+        restorePrsTestsDir = False
+
         if revision == "HEAD":
             subprocess.check_call(["git", "clone", "--depth=1", "--branch=%s" % branch, url, inDir])
         else:
             subprocess.check_call(["git", "clone", "--single-branch", "--branch=%s" % branch, url, inDir])
             subprocess.check_call(["git", "-C", inDir, "reset", "--hard", revision])
 
-        # Stash test262/local. Currently the test262 repo does not have any
-        # top-level subdirectory named "local".
-        restoreLocalTestsDir = False
-        if os.path.isdir(localTestsOutDir):
-            shutil.move(localTestsOutDir, inDir)
-            restoreLocalTestsDir = True
+        # If a PR number is provided, fetches only the new and modified files from that PR.
+        # It also creates a new folder for that PR or replaces if it already exists, without
+        # updating the regular Test262 tests.
+        if prNumber:
+            prTestsOutDir = os.path.join(prsTestsOutDir, prNumber)
+            if os.path.isdir(prTestsOutDir):
+                print("Removing folder %s" % prTestsOutDir)
+                shutil.rmtree(prTestsOutDir)
+
+            # Reuses current Test262 clone's harness and tools folders only, the clone's test/
+            # folder can be discarded from here
+            shutil.rmtree(os.path.join(inDir, "test"))
+
+            prRequest = requests.get("https://api.github.com/repos/tc39/test262/pulls/%s" % prNumber)
+            prRequest.raise_for_status()
+
+            pr = prRequest.json()
+
+            if (pr["state"] != "open"):
+                # Closed PR, remove respective files from folder
+                print("PR %s is closed" % prNumber)
+            else:
+                files = requests.get("https://api.github.com/repos/tc39/test262/pulls/%s/files" % prNumber)
+                files.raise_for_status()
+
+                for item in files.json():
+                    if not item["filename"].startswith("test/"):
+                        continue
+
+                    filename = item["filename"]
+                    fileStatus = item["status"]
+
+                    print("%s %s" % (fileStatus, filename))
+
+                    # Do not add deleted files
+                    if fileStatus == "removed":
+                        continue
 
-        # Create the output directory from scratch.
-        if os.path.isdir(outDir):
-            shutil.rmtree(outDir)
-        os.makedirs(outDir)
+                    contents = requests.get(item["raw_url"])
+                    contents.raise_for_status()
+
+                    fileText = contents.text
+
+                    # Prefix the PRs tests dir with test/ so files are processed as Test262 files
+                    prsTestsDir = "test/prs/%s" % prNumber
+                    filePathDirs = os.path.join(inDir, prsTestsDir, *filename.split("/")[1:-1])
+
+                    if not os.path.isdir(filePathDirs):
+                        os.makedirs(filePathDirs)
+
+                    filenameInDir = os.path.join(inDir, prsTestsDir, *filename.split("/")[1:])
 
-        # Copy license file.
-        shutil.copyfile(os.path.join(inDir, "LICENSE"), os.path.join(outDir, "LICENSE"))
+                    with open(filenameInDir, "wb") as output_file:
+                        output_file.write(fileText)
+        # Without a specific PR, follows through a regular copy.
+        else:
+            # Stash test262/local and test262/prs. Currently the Test262 repo does not have any
+            # top-level subdirectories named "local" or "prs".
+            # This prevents these folders from being removed during the update process.
+            if os.path.isdir(localTestsOutDir):
+                shutil.move(localTestsOutDir, inDir)
+                restoreLocalTestsDir = True
 
-        # Create the git info file.
-        with io.open(os.path.join(outDir, "GIT-INFO"), "wb") as info:
-            subprocess.check_call(["git", "-C", inDir, "log", "-1"], stdout=info)
+            if os.path.isdir(prsTestsOutDir):
+                shutil.move(prsTestsOutDir, inDir)
+                restorePrsTestsDir = True
+
+            # Create the output directory from scratch.
+            if os.path.isdir(outDir):
+                shutil.rmtree(outDir)
+            os.makedirs(outDir)
+
+            # Copy license file.
+            shutil.copyfile(os.path.join(inDir, "LICENSE"), os.path.join(outDir, "LICENSE"))
+
+            # Create the git info file.
+            with io.open(os.path.join(outDir, "GIT-INFO"), "wb") as info:
+                subprocess.check_call(["git", "-C", inDir, "log", "-1"], stdout=info)
 
         # Copy the test files.
         process_test262(inDir, outDir, strictTests)
 
         # Move test262/local back.
         if restoreLocalTestsDir:
             shutil.move(os.path.join(inDir, "local"), outDir)
 
+        # Restore test262/prs if necessary after a general Test262 update.
+        if restorePrsTestsDir:
+            shutil.move(os.path.join(inDir, "prs"), outDir)
+
 if __name__ == "__main__":
     import argparse
 
     # This script must be run from js/src/tests to work correctly.
     if "/".join(os.path.normpath(os.getcwd()).split(os.sep)[-3:]) != "js/src/tests":
         raise RuntimeError("%s must be run from js/src/tests" % sys.argv[0])
 
     parser = argparse.ArgumentParser(description="Update the test262 test suite.")
     parser.add_argument("--url", default="git://github.com/tc39/test262.git",
                         help="URL to git repository (default: %(default)s)")
     parser.add_argument("--branch", default="master",
                         help="Git branch (default: %(default)s)")
     parser.add_argument("--revision", default="HEAD",
                         help="Git revision (default: %(default)s)")
     parser.add_argument("--out", default="test262",
                         help="Output directory. Any existing directory will be removed! (default: %(default)s)")
+    parser.add_argument("--pull", help="Import contents from a Pull Request specified by its number")
     parser.add_argument("--strict", default=False, action="store_true",
                         help="Generate additional strict mode tests. Not enabled by default.")
     parser.set_defaults(func=update_test262)
     args = parser.parse_args()
     args.func(args)