automation: add a command to submit to a Try server
authorGregory Szorc <gregory.szorc@gmail.com>
Sat, 05 Oct 2019 11:21:39 -0400
changeset 43057 c5c502bd1f70
parent 43056 f71b3c561b93
child 43058 808a57a08470
automation: add a command to submit to a Try server The CI code for running the Try Server requires more thorough review. Let's add just the client-side bits for submitting to Try so others can start using it. Differential Revision: https://phab.mercurial-scm.org/D6983
contrib/automation/README.rst
contrib/automation/hgautomation/cli.py
contrib/automation/hgautomation/try_server.py
tests/test-check-code.t
--- a/contrib/automation/README.rst	Sat Oct 05 11:58:17 2019 -0400
+++ b/contrib/automation/README.rst	Sat Oct 05 11:21:39 2019 -0400
@@ -33,6 +33,46 @@
 into a remote machine, we create a temporary directory for the SSH
 config so the user's known hosts file isn't updated.
 
+Try Server
+==========
+
+There exists a *Try Server* which allows automation to run against
+an arbitrary Mercurial changeset and displays results via the web.
+
+.. note::
+
+   The *Try Server* is still experimental infrastructure.
+
+To use the *Try Server*::
+
+   $ ./automation.py try
+
+With a custom AWS profile::
+
+   $ AWS_PROFILE=hg contrib/automation/automation.py try
+
+By default, the ``.`` revision is submitted. **Any uncommitted changes
+are not submitted.**
+
+To switch which revision is used::
+
+   $ ./automation.py try -r abcdef
+
+Access to the *Try Server* requires access to a special AWS account.
+This account is currently run by Gregory Szorc. Here is the procedure
+for accessing the *Try Server*:
+
+1. Email Gregory Szorc at gregory.szorc@gmail.com and request a
+   username. This username will be stored in the public domain.
+2. Wait for an email reply containing your temporary AWS credentials.
+3. Log in at https://gregoryszorc-hg.signin.aws.amazon.com/console
+   and set a new, secure password.
+4. Go to https://console.aws.amazon.com/iam/home?region=us-west-2#/security_credentials
+5. Under ``Access keys for CLI, SDK, & API access``, click the
+   ``Create access key`` button.
+6. See the ``AWS Integration`` section for instructions on
+   configuring your local client to use the generated credentials.
+
 AWS Integration
 ===============
 
--- a/contrib/automation/hgautomation/cli.py	Sat Oct 05 11:58:17 2019 -0400
+++ b/contrib/automation/hgautomation/cli.py	Sat Oct 05 11:21:39 2019 -0400
@@ -17,6 +17,7 @@
     aws,
     HGAutomation,
     linux,
+    try_server,
     windows,
 )
 
@@ -193,6 +194,11 @@
                               ssh_username=ssh_username)
 
 
+def run_try(hga: HGAutomation, aws_region: str, rev: str):
+    c = hga.aws_connection(aws_region, ensure_ec2_state=False)
+    try_server.trigger_try(c, rev=rev)
+
+
 def get_parser():
     parser = argparse.ArgumentParser()
 
@@ -439,6 +445,15 @@
     )
     sp.set_defaults(func=publish_windows_artifacts)
 
+    sp = subparsers.add_parser(
+        'try',
+        help='Run CI automation against a custom changeset'
+    )
+    sp.add_argument('-r', '--rev',
+                    default='.',
+                    help='Revision to run CI on')
+    sp.set_defaults(func=run_try)
+
     return parser
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/automation/hgautomation/try_server.py	Sat Oct 05 11:21:39 2019 -0400
@@ -0,0 +1,99 @@
+# try_server.py - Interact with Try server
+#
+# Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+# no-check-code because Python 3 native.
+
+import base64
+import json
+import os
+import subprocess
+import tempfile
+
+from .aws import AWSConnection
+
+LAMBDA_FUNCTION = "ci-try-server-upload"
+
+
+def trigger_try(c: AWSConnection, rev="."):
+    """Trigger a new Try run."""
+    lambda_client = c.session.client("lambda")
+
+    cset, bundle = generate_bundle(rev=rev)
+
+    payload = {
+        "bundle": base64.b64encode(bundle).decode("utf-8"),
+        "node": cset["node"],
+        "branch": cset["branch"],
+        "user": cset["user"],
+        "message": cset["desc"],
+    }
+
+    print("resolved revision:")
+    print("node: %s" % cset["node"])
+    print("branch: %s" % cset["branch"])
+    print("user: %s" % cset["user"])
+    print("desc: %s" % cset["desc"].splitlines()[0])
+    print()
+
+    print("sending to Try...")
+    res = lambda_client.invoke(
+        FunctionName=LAMBDA_FUNCTION,
+        InvocationType="RequestResponse",
+        Payload=json.dumps(payload).encode("utf-8"),
+    )
+
+    body = json.load(res["Payload"])
+    for message in body:
+        print("remote: %s" % message)
+
+
+def generate_bundle(rev="."):
+    """Generate a bundle suitable for use by the Try service.
+
+    Returns a tuple of revision metadata and raw Mercurial bundle data.
+    """
+    # `hg bundle` doesn't support streaming to stdout. So we use a temporary
+    # file.
+    path = None
+    try:
+        fd, path = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
+        os.close(fd)
+
+        args = [
+            "hg",
+            "bundle",
+            "--type",
+            "gzip-v2",
+            "--base",
+            "public()",
+            "--rev",
+            rev,
+            path,
+        ]
+
+        print("generating bundle...")
+        subprocess.run(args, check=True)
+
+        with open(path, "rb") as fh:
+            bundle_data = fh.read()
+
+    finally:
+        if path:
+            os.unlink(path)
+
+    args = [
+        "hg",
+        "log",
+        "-r",
+        rev,
+        # We have to upload as JSON, so it won't matter if we emit binary
+        # since we need to normalize to UTF-8.
+        "-T",
+        "json",
+    ]
+    res = subprocess.run(args, check=True, capture_output=True)
+    return json.loads(res.stdout)[0], bundle_data
--- a/tests/test-check-code.t	Sat Oct 05 11:58:17 2019 -0400
+++ b/tests/test-check-code.t	Sat Oct 05 11:21:39 2019 -0400
@@ -18,6 +18,7 @@
   Skipping contrib/automation/hgautomation/linux.py it has no-che?k-code (glob)
   Skipping contrib/automation/hgautomation/pypi.py it has no-che?k-code (glob)
   Skipping contrib/automation/hgautomation/ssh.py it has no-che?k-code (glob)
+  Skipping contrib/automation/hgautomation/try_server.py it has no-che?k-code (glob)
   Skipping contrib/automation/hgautomation/windows.py it has no-che?k-code (glob)
   Skipping contrib/automation/hgautomation/winrm.py it has no-che?k-code (glob)
   Skipping contrib/packaging/hgpackaging/downloads.py it has no-che?k-code (glob)