You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2019/01/08 02:33:00 UTC

[GitHub] csantanapr closed pull request #87: switf4.2.1 with actionloop base implementation

csantanapr closed pull request #87: switf4.2.1 with actionloop base implementation
URL: https://github.com/apache/incubator-openwhisk-runtime-swift/pull/87
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/.gitignore b/.gitignore
index 039da65..100215f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,3 +73,8 @@ ansible/roles/nginx/files/*cert.pem
 !tests/dat/build/swift4.1/SwiftyRequestCodable.zip
 !tests/dat/build/swift4.1/HelloSwift4Codable.zip
 
+# Makefile artifacts
+test.json
+*.done
+examples/*/*.zip
+ActionLoop/
diff --git a/.travis.yml b/.travis.yml
index 1d530a6..b92ee9d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,7 +29,7 @@ deploy:
       all_branches: true
       repo: apache/incubator-openwhisk-runtime-swift
   - provider: script
-    script: "./tools/travis/publish.sh openwhisk 4.1 latest"
+    script: "./tools/travis/publish.sh openwhisk 4.1 latest && ./tools/travis/publish.sh openwhisk 4.2 latest"
     on:
       branch: master
       repo: apache/incubator-openwhisk-runtime-swift
diff --git a/README.md b/README.md
index a14b034..4f3cefd 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@
 ## Changelogs
 - [Swift 3.1.1 CHANGELOG.md](core/swift3.1.1Action/CHANGELOG.md)
 - [Swift 4.1   CHANGELOG.md](core/swift41Action/CHANGELOG.md)
+- [Swift 4.2   CHANGELOG.md](core/swift42Action/CHANGELOG.md)
 
 ## Quick Swift Action
 ### Simple swift action hello.swift
@@ -57,7 +58,7 @@ func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
 }
 ```
 ```
-wsk action update helloCodableAsync helloCodableAsync.swift swift:4.1
+wsk action update helloCodableAsync helloCodableAsync.swift swift:4.2
 ```
 ```
 ok: updated action helloCodableAsync
@@ -94,7 +95,7 @@ func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
 }
 ```
 ```
-wsk action update helloCodableError helloCodableError.swift swift:4.1
+wsk action update helloCodableError helloCodableError.swift swift:4.2
 ```
 ```
 ok: updated action helloCodableError
@@ -114,15 +115,37 @@ wsk action invoke helloCodableError -b -p id 42 -p name Carlos
 }
 ```
 
-### Packaging an action as a Swift executable using Swift 4
+## Packaging an action as a Swift executable using Swift 4.x
 
 When you create an OpenWhisk Swift action with a Swift source file, it has to be compiled into a binary before the action is run. Once done, subsequent calls to the action are much faster until the container holding your action is purged. This delay is known as the cold-start delay.
 
-To avoid the cold-start delay, you can compile your Swift file into a binary and then upload to OpenWhisk in a zip file. As you need the OpenWhisk scaffolding, the easiest way to create the binary is to build it within the same environment as it will be run in. These are the steps:
+To avoid the cold-start delay, you can compile your Swift file into a binary and then upload to OpenWhisk in a zip file. As you need the OpenWhisk scaffolding, the easiest way to create the binary is to build it within the same environment as it will be run in.
+
+### Compiling Swift 4.2
+
+### Compiling Swift 4.2 single file
+
+Use the docker container and pass the single source file as stdin.
+Pass the name of the method to the flag `-compile`
+```
+docker run -i openwhisk/action-swift-v4.2 -compile main <main.swift >../action.zip
+```
+
+### Compiling Swift 4.2 multiple files with dependencies
+Use the docker container and pass a zip archive containing a `Package.swift` and source files a main source file in the location `Sources/main.swift`.
+```
+zip - -r * | docker run -i openwhisk/action-swift-v4.2 -compile main >../action.zip
+```
+
+For more build examples see [here](./examples/)
+
+
+### Compiling Swift 4.1
+These are the steps:
 
 - Run an interactive Swift action container.
   ```
-  docker run --rm -it -v "$(pwd):/owexec" openwhisk/action-swift-v4.1 bash
+  docker run --rm -it -v "$(pwd):/owexec" openwhisk/action-swift-v4.2 bash
   ```
   This puts you in a bash shell within the Docker container.
 
@@ -139,7 +162,7 @@ To avoid the cold-start delay, you can compile your Swift file into a binary and
   Copy any additional source files to `/swift4Action/spm-build/Sources/Action/`
 
 
-- (Optional) Create the `Package.swift` file to add dependencies.
+- Create the `Package.swift` file to add dependencies.
 ```swift
 // swift-tools-version:4.0
 // The swift-tools-version declares the minimum version of Swift required to build this package.
@@ -167,7 +190,7 @@ let package = Package(
 ```
   As you can see this example adds `SwiftyRequest` dependencies.
 
-  Notice that now with swift:4.1 is no longer required to include `CCurl`, `Kitura-net` and `SwiftyJSON` in your own `Package.swift`.
+  Notice that now with swift:4.2 is no longer required to include `CCurl`, `Kitura-net` and `SwiftyJSON` in your own `Package.swift`.
   You are free now to use no dependencies, or add the combination that you want with the versions you want.
 
 - Copy Package.swift to spm-build directory
@@ -199,7 +222,7 @@ let package = Package(
 
 - Upload it to OpenWhisk with the action name helloSwifty:
   ```
-  wsk action update helloSwiftly hello.zip openwhisk/action-swift-v4.1
+  wsk action update helloSwiftly hello.zip openwhisk/action-swift-v4.2
   ```
 
 - To check how much faster it is, run
@@ -224,15 +247,15 @@ Having a project directory `Hello` under a directory `actions` like the followin
 actions/Hello/Package.swift
 actions/Hello/Sources/main.swift
 ```
-Change to the parent directory then run the compile script specify the project directory, the kind `swift:3.1.1` or `swift:4.1` and any swiftc build flags like the following:
+Change to the parent directory then run the compile script specify the project directory, the kind `swift:3.1.1` or `swift:4.2` and any swiftc build flags like the following:
 ```
 cd actions/
-incubator-runtime-swift/tools/build/compile.sh Hello swift:4.1 -v
+incubator-runtime-swift/tools/build/compile.sh Hello swift:4.2 -v
 ```
 This will produce a zip `build/swift4/Hello.zip`
 
 ### SwiftyJSON using single source action file
-If you have a swift:3.1.1 action not compile, just as source using the `SwiftyJSON` package, you need to precompile your action and specify the version of SwiftyJSON you wan to use for swift:4.1 kind action.
+If you have a swift:3.1.1 action not compile, just as source using the `SwiftyJSON` package, you need to precompile your action and specify the version of SwiftyJSON you wan to use for swift:4.2 kind action.
 Take into account that starting with Swift 4 there is better support to manage JSON data natively.
 
 Note: This is only applicable to the base image provided for the Swift 4 runtime, other downstream such as IBM Cloud Functions extending this image might provide additional SDK and packages including `SwiftyJSON` and IBM Watson SDK, check the vendor documentation for more specific information about packages and versions.
@@ -241,7 +264,7 @@ Note: This is only applicable to the base image provided for the Swift 4 runtime
 ```
 ./gradlew core:swift40Action:distDocker
 ```
-This will produce the image `whisk/action-swift-v4.1`
+This will produce the image `whisk/action-swift-v4.2`
 
 Build and Push image
 ```
@@ -249,10 +272,6 @@ docker login
 ./gradlew core:swift40Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io
 ```
 
-### Swift 4.1 Experimental
-We have a runtime for swift 4.1, is experimental as we are trying beta builds released by Swift org.
-Follow same insructions for Swift 4.1 above and replace the kind wih `swift:4.1` and image with `openwhisk/action-swift-v4.1`
-
 
 ## Codable Suppor with Swift 4.x
 
@@ -273,7 +292,7 @@ func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
 }
 ```
 ```
-wsk action update helloCodableAsync helloCodableAsync.swift swift:4.1
+wsk action update helloCodableAsync helloCodableAsync.swift swift:4.2
 ```
 ```
 ok: updated action helloCodableAsync
@@ -310,7 +329,7 @@ func main(input: Employee, respondWith: (Employee?, Error?) -> Void) -> Void {
 }
 ```
 ```
-wsk action update helloCodableError helloCodableError.swift swift:4.1
+wsk action update helloCodableError helloCodableError.swift swift:4.2
 ```
 ```
 ok: updated action helloCodableError
@@ -331,24 +350,24 @@ wsk action invoke helloCodableError -b -p id 42 -p name Carlos
 }
 ```
 
-### Using Swift 4.1
+### Using Swift 4.2
 To use as a docker action
 ```
-wsk action update myAction myAction.swift --docker openwhisk/action-swift-v4.1:1.0.7
+wsk action update myAction myAction.swift --docker openwhisk/action-swift-v4.2:1.0.7
 ```
 This works on any deployment of Apache OpenWhisk
 
 ### To use on deployment that contains the rutime as a kind
 To use as a kind action
 ```
-wsk action update myAction myAction.swift --kind swift:4.1
+wsk action update myAction myAction.swift --kind swift:4.2
 ```
 
 ## Local development
 ```
 ./gradlew core:swift41Action:distDocker
 ```
-This will produce the image `whisk/action-swift-v4.1`
+This will produce the image `whisk/action-swift-v4.2`
 
 Build and Push image
 ```
@@ -356,7 +375,7 @@ docker login
 ./gradlew core:swift41Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io
 ```
 
-Deploy OpenWhisk using ansible environment that contains the kind `swift:4.1`
+Deploy OpenWhisk using ansible environment that contains the kind `swift:4.2`
 Assuming you have OpenWhisk already deploy localy and `OPENWHISK_HOME` pointing to root directory of OpenWhisk core repository.
 
 Set `ROOTDIR` to the root directory of this repository.
@@ -400,12 +419,12 @@ Using IntelliJ:
 #### Using container image to test
 To use as docker action push to your own dockerhub account
 ```
-docker tag whisk/action-swift-v4.1 $user_prefix/action-swift-v4.1
-docker push $user_prefix/action-swift-v4.1
+docker tag whisk/action-swift-v4.2 $user_prefix/action-swift-v4.2
+docker push $user_prefix/action-swift-v4.2
 ```
 Then create the action using your the image from dockerhub
 ```
-wsk action update myAction myAction.swift --docker $user_prefix/action-swift-v4.1
+wsk action update myAction myAction.swift --docker $user_prefix/action-swift-v4.2
 ```
 The `$user_prefix` is usually your dockerhub user id.
 
diff --git a/ansible/environments/local/group_vars/all b/ansible/environments/local/group_vars/all
index 4caf10e..64dd3f0 100755
--- a/ansible/environments/local/group_vars/all
+++ b/ansible/environments/local/group_vars/all
@@ -50,10 +50,15 @@ runtimes_manifest:
         name: "action-swift-v3.1.1"
       deprecated: false
     - kind: "swift:4.1"
-      default: true
+      default: false
       image:
         name: "action-swift-v4.1"
       deprecated: false
+    - kind: "swift:4.2"
+      default: true
+      image:
+        name: "action-swift-v4.2"
+      deprecated: false
 
   blackboxes:
     - name: "dockerskeleton"
diff --git a/core/swift42Action/Dockerfile b/core/swift42Action/Dockerfile
new file mode 100644
index 0000000..e3e018b
--- /dev/null
+++ b/core/swift42Action/Dockerfile
@@ -0,0 +1,48 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+FROM openwhisk/actionloop as builder
+
+FROM swift:4.2
+
+RUN rm -rf /var/lib/apt/lists/* && apt-get clean && apt-get update \
+	&& apt-get install -y --no-install-recommends locales python3 vim \
+	&& rm -rf /var/lib/apt/lists/* \
+	&& locale-gen en_US.UTF-8
+
+ENV LANG="en_US.UTF-8" \
+	LANGUAGE="en_US:en" \
+	LC_ALL="en_US.UTF-8"
+
+RUN mkdir -p /swiftAction
+WORKDIR /swiftAction
+
+
+COPY --from=builder /bin/proxy /bin/proxy
+ADD swiftbuild.py /bin/compile
+ADD swiftbuild.py.launcher.swift /bin/compile.launcher.swift
+COPY _Whisk.swift /swiftAction/Sources/
+COPY Package.swift /swiftAction/
+COPY buildandrecord.py /swiftAction/
+COPY main.swift /swiftAction/Sources/
+RUN swift build -c release; \
+touch /swiftAction/Sources/main.swift; \
+rm /swiftAction/.build/release/Action; \
+/swiftAction/buildandrecord.py
+
+
+ENV OW_COMPILER=/bin/compile
+ENTRYPOINT [ "/bin/proxy" ]
diff --git a/core/swift42Action/Package.swift b/core/swift42Action/Package.swift
new file mode 100644
index 0000000..181e352
--- /dev/null
+++ b/core/swift42Action/Package.swift
@@ -0,0 +1,37 @@
+// swift-tools-version:4.2
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import PackageDescription
+
+let package = Package(
+    name: "Action",
+    products: [
+      .executable(
+        name: "Action",
+        targets:  ["Action"]
+      )
+    ],
+    targets: [
+      .target(
+        name: "Action",
+        path: "."
+      )
+    ]
+)
diff --git a/core/swift42Action/build.gradle b/core/swift42Action/build.gradle
new file mode 100755
index 0000000..117edc2
--- /dev/null
+++ b/core/swift42Action/build.gradle
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ext.dockerImageName = 'action-swift-v4.2'
+apply from: '../../gradle/docker.gradle'
+
+distDocker.dependsOn 'copyWhisk'
+distDocker.finalizedBy('cleanup')
+
+task copyWhisk(type: Copy) {
+    from '../swift41Action/spm-build/_Whisk.swift'
+    into '_Whisk.swift'
+}
+
+task cleanup(type: Delete) {
+    delete '_Whisk.swift'
+}
diff --git a/core/swift42Action/buildandrecord.py b/core/swift42Action/buildandrecord.py
new file mode 100755
index 0000000..bc15f06
--- /dev/null
+++ b/core/swift42Action/buildandrecord.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python3
+"""Python to generate build script.
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+"""
+from __future__ import print_function
+import os
+import sys
+from subprocess import check_output
+
+# Settings
+COMPILE_PREFIX = "/usr/bin/swiftc -module-name Action "
+LINKER_PREFIX =  "/usr/bin/swiftc -target x86_64-unknown-linux -sdk / -L /swiftAction/.build/x86_64-unknown-linux/release -o /swiftAction/.build/x86_64-unknown-linux/release/Action -module-name Action -emit-executable -Xlinker '-rpath=$ORIGIN'"
+GENERATED_BUILD_SCRIPT = "/swiftAction/swiftbuildandlink.sh"
+SPM_DIRECTORY = "/swiftAction"
+BUILD_COMMAND = ["swift", "build", "-v", "-c", "release"]
+
+# Build Swift package and capture step trace
+print("Building action")
+out = check_output(BUILD_COMMAND, cwd=SPM_DIRECTORY)
+print("action built. Decoding compile and link commands")
+
+# Look for compile and link commands in step trace
+compileCommand = None
+linkCommand = None
+
+buildInstructions = out.decode("utf-8").splitlines()
+
+for instruction in buildInstructions:
+    print(instruction)
+    if instruction.startswith(COMPILE_PREFIX):
+        compileCommand = instruction
+
+        # add flag to quiet warnings
+        compileCommand += " -suppress-warnings"
+
+    elif instruction.startswith(LINKER_PREFIX):
+        linkCommand = instruction
+
+# if found, create build script, otherwise exit with error
+if compileCommand is not None and linkCommand is not None:
+    print("Generated OpenWhisk Compile command: %s" % compileCommand)
+    print("=========")
+    print("Generated OpenWhisk Link command: %s" % linkCommand)
+
+    with open(GENERATED_BUILD_SCRIPT, "w") as buildScript:
+        buildScript.write("#!/bin/bash\n")
+        buildScript.write("#date\n")
+        buildScript.write("#echo \"Compiling\"\n")
+        buildScript.write("%s\n" % compileCommand)
+        buildScript.write("swiftStatus=$?\n")
+        buildScript.write("#echo swiftc status is $swiftStatus\n")
+        buildScript.write("if [[ \"$swiftStatus\" -eq \"0\" ]]; then\n")
+        buildScript.write("#date\n")
+        buildScript.write("#echo \"Linking\"\n")
+        buildScript.write("%s\n" % linkCommand)
+        buildScript.write("#date\n")
+        buildScript.write("else\n")
+        buildScript.write(">2& echo \"Action did not compile\"\n")
+        buildScript.write("exit 1\n")
+        buildScript.write("fi")
+
+    os.chmod(GENERATED_BUILD_SCRIPT, 0o777)
+    sys.exit(0)
+else:
+    print("Cannot generate build script: compile or link command not found")
+    sys.exit(1)
diff --git a/core/swift42Action/main.swift b/core/swift42Action/main.swift
new file mode 100644
index 0000000..75071a3
--- /dev/null
+++ b/core/swift42Action/main.swift
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+func main(args: [String:Any]) -> [String:Any] {
+    if let name = args["name"] as? String {
+        return [ "greeting" : "Hello \(name)!" ]
+    } else {
+        return [ "greeting" : "Hello stranger!" ]
+    }
+}
diff --git a/core/swift42Action/swiftbuild.py b/core/swift42Action/swiftbuild.py
new file mode 100755
index 0000000..9b40903
--- /dev/null
+++ b/core/swift42Action/swiftbuild.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+"""Swift Action Compiler
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+
+from __future__ import print_function
+import os
+import re
+import sys
+import codecs
+import subprocess
+from io import StringIO
+
+def eprint(*args, **kwargs):
+    print(*args, file=sys.stderr, **kwargs)
+
+def sources(launcher, source_dir, main):
+    actiondir = "%s/Sources" % source_dir
+    # copy the launcher fixing the main
+    dst = "%s/main.swift" % actiondir
+    with codecs.open(dst, 'a', 'utf-8') as d:
+        with codecs.open(launcher, 'r', 'utf-8') as e:
+            code = e.read()
+            code += "while let inputStr: String = readLine() {\n"
+            code += "  let json = inputStr.data(using: .utf8, allowLossyConversion: true)!\n"
+            code += "  let parsed = try JSONSerialization.jsonObject(with: json, options: []) as! [String: Any]\n"
+            code += "  for (key, value) in parsed {\n"
+            code += "    if key != \"value\" {\n"
+            code += "      setenv(\"__OW_\\(key.uppercased())\",value as! String,1)\n"
+            code += "    }\n"
+            code += "  }\n"
+            code += "  let jsonData = try JSONSerialization.data(withJSONObject: parsed[\"value\"] as Any, options: [])\n"
+            code += "  _run_main(mainFunction: %s, json: jsonData)\n" % main
+            code += "} \n"
+            d.write(code)
+
+def swift_build(dir, buildcmd):
+    # compile...
+    env = {
+      "PATH": os.environ["PATH"]
+    }
+    p = subprocess.Popen(buildcmd,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        cwd=dir,
+        env=env)
+    (o, e) = p.communicate()
+    # stdout/stderr may be either text or bytes, depending on Python
+    # version, so if bytes, decode to text. Note that in Python 2
+    # a string will match both types; so also skip decoding in that case
+    if isinstance(o, bytes) and not isinstance(o, str):
+        o = o.decode('utf-8')
+    if isinstance(e, bytes) and not isinstance(e, str):
+        e = e.decode('utf-8')
+    return p.returncode, o, e
+
+def build(source_dir, target_file, buildcmd):
+    r, o, e = swift_build(source_dir, buildcmd)
+    #if e: print(e)
+    #if o: print(o)
+    if r != 0:
+        print(e)
+        print(o)
+        print(r)
+        return
+
+    bin_file = "%s/.build/release/Action" % source_dir
+    os.rename(bin_file, target_file)
+    if not os.path.isfile(target_file):
+        print("failed %s -> %s" % (bin_file, target_file))
+        return
+
+
+def main(argv):
+    if len(argv) < 4:
+        print("usage: <main-function> <source-dir> <target-dir>")
+        sys.exit(1)
+
+    main = argv[1]
+    source_dir = os.path.abspath(argv[2])
+    target = os.path.abspath("%s/exec" % argv[3])
+    launch = os.path.abspath(argv[0]+".launcher.swift")
+
+    src = "%s/exec" % source_dir
+
+    #check if single source
+    if os.path.isfile(src):
+        actiondir = os.path.abspath("Sources")
+        if not os.path.isdir(actiondir):
+            os.makedirs(actiondir, mode=0o755)
+        dst = "%s/main.swift" % actiondir
+        os.rename(src, dst)
+        sources(launch, os.path.abspath("."), main)
+        build(os.path.abspath("."), target, ["./swiftbuildandlink.sh"])
+    else:
+        actiondir = "%s/Sources" % source_dir
+        if not os.path.isdir(actiondir):
+            os.makedirs(actiondir, mode=0o755)
+        os.rename(os.path.abspath("Sources/_Whisk.swift"),"%s/Sources/_Whisk.swift" % source_dir)
+        sources(launch, source_dir, main)
+        build(source_dir, target, ["swift", "build", "-c", "release"])
+
+if __name__ == '__main__':
+    main(sys.argv)
diff --git a/core/swift42Action/swiftbuild.py.launcher.swift b/core/swift42Action/swiftbuild.py.launcher.swift
new file mode 100644
index 0000000..bf6b65d
--- /dev/null
+++ b/core/swift42Action/swiftbuild.py.launcher.swift
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Imports
+import Foundation
+#if os(Linux)
+    import Glibc
+#else
+    import Darwin
+#endif
+
+func _whisk_print_error(message: String, error: Error?){
+    var errStr =  "{\"error\":\"\(message)\"}\n"
+    if let error = error {
+        errStr = "{\"error\":\"\(message) \(error.localizedDescription)\"\n}"
+    }
+    _whisk_print_buffer(jsonString: errStr)
+}
+func _whisk_print_result(jsonData: Data){
+    let jsonString = String(data: jsonData, encoding: .utf8)!
+    _whisk_print_buffer(jsonString: jsonString)
+}
+func _whisk_print_buffer(jsonString: String){
+    var buf : [UInt8] = Array(jsonString.utf8)
+    buf.append(10)
+    write(3, buf, buf.count)
+    fflush(stdout)
+    fflush(stderr)
+}
+
+// snippet of code "injected" (wrapper code for invoking traditional main)
+func _run_main(mainFunction: ([String: Any]) -> [String: Any], json: Data) -> Void {
+    do {
+        let parsed = try JSONSerialization.jsonObject(with: json, options: []) as! [String: Any]
+        let result = mainFunction(parsed)
+        if JSONSerialization.isValidJSONObject(result) {
+            do {
+                let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
+                 _whisk_print_result(jsonData: jsonData)
+            } catch {
+                _whisk_print_error(message: "Failed to encode Dictionary type to JSON string:", error: error)
+            }
+        } else {
+            _whisk_print_error(message: "Error serializing JSON, data does not appear to be valid JSON", error: nil)
+        }
+    } catch {
+        _whisk_print_error(message: "Failed to execute action handler with error:", error: error)
+        return
+    }
+}
+
+// Codable main signature input Codable
+func _run_main<In: Decodable, Out: Encodable>(mainFunction: (In, @escaping (Out?, Error?) -> Void) -> Void, json: Data) {
+    do {
+        let input = try Whisk.jsonDecoder.decode(In.self, from: json)
+        let resultHandler = { (out: Out?, error: Error?) in
+            if let error = error {
+                _whisk_print_error(message: "Action handler callback returned an error:", error: error)
+                return
+            }
+            guard let out = out else {
+                _whisk_print_error(message: "Action handler callback did not return response or error.", error: nil)
+                return
+            }
+            do {
+                let jsonData = try Whisk.jsonEncoder.encode(out)
+                _whisk_print_result(jsonData: jsonData)
+            } catch let error as EncodingError {
+                _whisk_print_error(message: "JSONEncoder failed to encode Codable type to JSON string:", error: error)
+                return
+            } catch {
+                _whisk_print_error(message: "Failed to execute action handler with error:", error: error)
+                return
+            }
+        }
+        let _ = mainFunction(input, resultHandler)
+    } catch let error as DecodingError {
+        _whisk_print_error(message: "JSONDecoder failed to decode JSON string \(String(data: json, encoding: .utf8)!.replacingOccurrences(of: "\"", with: "\\\"")) to Codable type:", error: error)
+        return
+    } catch {
+        _whisk_print_error(message: "Failed to execute action handler with error:", error: error)
+        return
+    }
+}
+
+// Codable main signature no input
+func _run_main<Out: Encodable>(mainFunction: ( @escaping (Out?, Error?) -> Void) -> Void, json: Data) {
+    let resultHandler = { (out: Out?, error: Error?) in
+        if let error = error {
+            _whisk_print_error(message: "Action handler callback returned an error:", error: error)
+            return
+        }
+        guard let out = out else {
+            _whisk_print_error(message: "Action handler callback did not return response or error.", error: nil)
+            return
+        }
+        do {
+            let jsonData = try Whisk.jsonEncoder.encode(out)
+            _whisk_print_result(jsonData: jsonData)
+        } catch let error as EncodingError {
+            _whisk_print_error(message: "JSONEncoder failed to encode Codable type to JSON string:", error: error)
+            return
+        } catch {
+            _whisk_print_error(message: "Failed to execute action handler with error:", error: error)
+            return
+        }
+    }
+    let _ = mainFunction(resultHandler)
+}
+
+// snippets of code "injected", dependending on the type of function the developer
+// wants to use traditional vs codable
+
+
+
+
+
+
+
diff --git a/examples/swift-main-single/Makefile b/examples/swift-main-single/Makefile
new file mode 100644
index 0000000..83950ca
--- /dev/null
+++ b/examples/swift-main-single/Makefile
@@ -0,0 +1,35 @@
+OW_USER?=whisk
+OW_RUNTIME?=$(OW_USER)/action-swift-v4.2
+OW_COMPILER?=$(OW_USER)/action-swift-v4.2
+WSK?=wsk -i
+MAIN=main
+PACKAGE=test
+SRC=$(MAIN).swift
+NAME=swift-$(MAIN)-single
+ZIP=$(MAIN).zip
+
+deploy: package.done $(ZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(ZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRC)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRC) --main $(MAIN) --docker $(OW_COMPILER)
+
+$(ZIP): $(SRC)
+	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRC) >$(ZIP)
+
+clean:
+	wsk action delete $(PACKAGE)/$(NAME)
+	rm $(ZIP) package.done
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
diff --git a/examples/swift-main-single/main.swift b/examples/swift-main-single/main.swift
new file mode 100644
index 0000000..9a7aaf8
--- /dev/null
+++ b/examples/swift-main-single/main.swift
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+func main(args: [String:Any]) -> [String:Any] {
+    if let name = args["name"] as? String {
+        return [ "greeting" : "Hello \(name)!" ]
+    } else {
+        return [ "greeting" : "Hello swif4.2!" ]
+    }
+}
+
+func mainenv(args: [String: Any]) -> [String: Any] {
+     let env = ProcessInfo.processInfo.environment
+     var a = "???"
+     var b = "???"
+     var c = "???"
+     var d = "???"
+     var e = "???"
+     var f = "???"
+     if let v : String = env["__OW_API_HOST"] {
+         a = "\(v)"
+     }
+     if let v : String = env["__OW_API_KEY"] {
+         b = "\(v)"
+     }
+     if let v : String = env["__OW_NAMESPACE"] {
+         c = "\(v)"
+     }
+     if let v : String = env["__OW_ACTION_NAME"] {
+         d = "\(v)"
+     }
+     if let v : String = env["__OW_ACTIVATION_ID"] {
+         e = "\(v)"
+     }
+     if let v : String = env["__OW_DEADLINE"] {
+         f = "\(v)"
+     }
+     return ["api_host": a, "api_key": b, "namespace": c, "action_name": d, "activation_id": e, "deadline": f]
+}
diff --git a/examples/swift-main-zip/HelloSwift4/Package.swift b/examples/swift-main-zip/HelloSwift4/Package.swift
new file mode 100644
index 0000000..181e352
--- /dev/null
+++ b/examples/swift-main-zip/HelloSwift4/Package.swift
@@ -0,0 +1,37 @@
+// swift-tools-version:4.2
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import PackageDescription
+
+let package = Package(
+    name: "Action",
+    products: [
+      .executable(
+        name: "Action",
+        targets:  ["Action"]
+      )
+    ],
+    targets: [
+      .target(
+        name: "Action",
+        path: "."
+      )
+    ]
+)
diff --git a/examples/swift-main-zip/HelloSwift4/Sources/main.swift b/examples/swift-main-zip/HelloSwift4/Sources/main.swift
new file mode 100644
index 0000000..2bd6836
--- /dev/null
+++ b/examples/swift-main-zip/HelloSwift4/Sources/main.swift
@@ -0,0 +1,10 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more contributor
+// license agreements; and to You under the Apache License, Version 2.0.
+
+func main(args: [String:Any]) -> [String:Any] {
+    if let name = args["name"] as? String {
+        return [ "greeting" : "Hello \(name)!" ]
+    } else {
+        return [ "greeting" : "Hello stranger!" ]
+    }
+}
diff --git a/examples/swift-main-zip/Makefile b/examples/swift-main-zip/Makefile
new file mode 100644
index 0000000..2f05476
--- /dev/null
+++ b/examples/swift-main-zip/Makefile
@@ -0,0 +1,39 @@
+OW_USER?=whisk
+OW_RUNTIME?=$(OW_USER)/action-swift-v4.2
+OW_COMPILER?=$(OW_USER)/action-swift-v4.2
+WSK?=wsk -i
+MAIN=main
+PACKAGE=test
+SRCS=HelloSwift4/Sources/$(MAIN).swift HelloSwift4/Package.swift
+NAME=swift-$(MAIN)-zip
+BINZIP=$(MAIN)-bin.zip
+SRCZIP=$(MAIN)-src.zip
+
+deploy: package.done $(BINZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME)
+
+devel: package.done $(SRCZIP)
+	$(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER)
+
+$(BINZIP): $(SRCS)
+	cd HelloSwift4 ; zip - -r * | docker run -i $(OW_COMPILER) -compile $(MAIN) >../$(BINZIP)
+
+$(SRCZIP): $(SRCS)
+	cd HelloSwift4 ; zip ../$(SRCZIP) -r *
+
+clean:
+	-$(WSK) action delete $(PACKAGE)/$(NAME)
+	-rm  $(BINZIP) $(SRCZIP) package.done test.json
+
+test: test.json
+	$(WSK) action invoke test/$(NAME) -r
+	$(WSK) action invoke test/$(NAME) -P test.json -r
+
+test.json:
+	echo '{ "name": "Mike" }' >test.json
+
+package.done:
+	$(WSK) package update $(PACKAGE)
+	touch package.done
+
+.PHONY: deploy devel test clean
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 0009fa4..7b18e3c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -21,6 +21,8 @@ include 'core:swift3.1.1Action'
 
 include 'core:swift41Action'
 
+include 'core:swift42Action'
+
 rootProject.name = 'runtime-swift'
 
 gradle.ext.openwhisk = [
diff --git a/tests/dat/actions/Makefile b/tests/dat/actions/Makefile
new file mode 100644
index 0000000..2469e53
--- /dev/null
+++ b/tests/dat/actions/Makefile
@@ -0,0 +1,30 @@
+OW_USER?=whisk
+OW_COMPILER?=$(OW_USER)/action-swift-v4.2
+OUT?=../../build/swift4.2
+define Build
+	cd $(1); \
+	docker run -i $(OW_COMPILER) -compile main <./Sources/main.swift >$(OUT)/$(1).zip
+endef
+
+define BuildWithLib
+	cd $(1); \
+	sed -i.bak 's/4.0/4.2/' Package.swift; \
+	zip - -r Package.swift Sources/main.swift | docker run -i $(OW_COMPILER) -compile main >$(OUT)/$(1).zip; \
+	mv Package.swift.bak Package.swift
+endef
+
+Hello:
+	$(call Build,HelloSwift4)
+
+HelloCodable:
+	$(call Build,HelloSwift4Codable)
+
+Swifty:
+	$(call BuildWithLib,SwiftyRequest)
+
+SwiftyCodable:
+	$(call BuildWithLib,SwiftyRequestCodable)
+
+all: Hello HelloCodable Swifty SwiftyCodable
+
+.PHONY: Hello HelloCodable Swifty SwiftyCodable
\ No newline at end of file
diff --git a/tests/dat/build.sh b/tests/dat/build.sh
index 3df8598..9511cbc 100755
--- a/tests/dat/build.sh
+++ b/tests/dat/build.sh
@@ -10,3 +10,6 @@ set -e
 ../../tools/build/compile.sh  SwiftyRequest swift:4.1 "-v"
 ../../tools/build/compile.sh  SwiftyRequestCodable swift:4.1 "-v"
 ../../tools/build/compile.sh  HelloSwift4Codable swift:4.1 "-v"
+
+cd actions
+make all
diff --git a/tests/dat/build/swift4.2/HelloSwift4.zip b/tests/dat/build/swift4.2/HelloSwift4.zip
new file mode 100644
index 0000000..9d4b85d
Binary files /dev/null and b/tests/dat/build/swift4.2/HelloSwift4.zip differ
diff --git a/tests/dat/build/swift4.2/HelloSwift4Codable.zip b/tests/dat/build/swift4.2/HelloSwift4Codable.zip
new file mode 100644
index 0000000..2a26962
Binary files /dev/null and b/tests/dat/build/swift4.2/HelloSwift4Codable.zip differ
diff --git a/tests/dat/build/swift4.2/SwiftyRequest.zip b/tests/dat/build/swift4.2/SwiftyRequest.zip
new file mode 100644
index 0000000..c57adc3
Binary files /dev/null and b/tests/dat/build/swift4.2/SwiftyRequest.zip differ
diff --git a/tests/dat/build/swift4.2/SwiftyRequestCodable.zip b/tests/dat/build/swift4.2/SwiftyRequestCodable.zip
new file mode 100644
index 0000000..ca0568b
Binary files /dev/null and b/tests/dat/build/swift4.2/SwiftyRequestCodable.zip differ
diff --git a/tests/src/test/scala/runtime/actionContainers/Swift311ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/Swift311ActionContainerTests.scala
index cf8ede6..d23d383 100644
--- a/tests/src/test/scala/runtime/actionContainers/Swift311ActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/Swift311ActionContainerTests.scala
@@ -179,4 +179,58 @@ class Swift311ActionContainerTests extends SwiftActionContainerTests {
         e shouldBe empty
     })
   }
+
+  // TODO
+  // skip for swift 4.2, it responds with 502 on init, stderr doesn't contain compile errors
+  // compile errors are contained in result
+  it should "log compilation errors" in {
+    val (out, err) = withActionContainer() { c =>
+      val code = """
+                   | 10 PRINT "Hello!"
+                   | 20 GOTO 10
+                 """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should not be (200)
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        e.toLowerCase should include("error")
+    })
+  }
+
+  // TODO
+  // swift 4.2 exceptions executable exiting doesn't return error from web proxy or ends container
+  // the action times out
+  it should "return some error on action error" in {
+    val (out, err) = withActionContainer() { c =>
+      val code = """
+                   | // You need an indirection, or swiftc detects the div/0
+                   | // at compile-time. Smart.
+                   | func div(x: Int, y: Int) -> Int {
+                   |     return x/y
+                   | }
+                   | func main(args: [String: Any]) -> [String: Any] {
+                   |     return [ "divBy0": div(x:5, y:0) ]
+                   | }
+                 """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runCode should be(502)
+
+      runRes shouldBe defined
+      runRes.get.fields.get("error") shouldBe defined
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        if (enforceEmptyOutputStream) e shouldBe empty
+    })
+  }
 }
diff --git a/tests/src/test/scala/runtime/actionContainers/Swift41ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/Swift41ActionContainerTests.scala
index d96db53..ee4f6bd 100644
--- a/tests/src/test/scala/runtime/actionContainers/Swift41ActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/Swift41ActionContainerTests.scala
@@ -115,4 +115,58 @@ class Swift41ActionContainerTests extends SwiftActionContainerTests {
         e shouldBe empty
     })
   }
+
+  // TODO
+  // skip for swift 4.2, it responds with 502 on init, stderr doesn't contain compile errors
+  // compile errors are contained in result
+  it should "log compilation errors" in {
+    val (out, err) = withActionContainer() { c =>
+      val code = """
+                   | 10 PRINT "Hello!"
+                   | 20 GOTO 10
+                 """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should not be (200)
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        e.toLowerCase should include("error")
+    })
+  }
+
+  // TODO
+  // swift 4.2 exceptions executable exiting doesn't return error from web proxy or ends container
+  // the action times out
+  it should "return some error on action error" in {
+    val (out, err) = withActionContainer() { c =>
+      val code = """
+                   | // You need an indirection, or swiftc detects the div/0
+                   | // at compile-time. Smart.
+                   | func div(x: Int, y: Int) -> Int {
+                   |     return x/y
+                   | }
+                   | func main(args: [String: Any]) -> [String: Any] {
+                   |     return [ "divBy0": div(x:5, y:0) ]
+                   | }
+                 """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runCode should be(502)
+
+      runRes shouldBe defined
+      runRes.get.fields.get("error") shouldBe defined
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        if (enforceEmptyOutputStream) e shouldBe empty
+    })
+  }
 }
diff --git a/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
index cd0a8ba..618f704 100644
--- a/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
@@ -19,9 +19,46 @@ package runtime.actionContainers
 
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
+import spray.json.JsObject
 
 @RunWith(classOf[JUnitRunner])
 class Swift41CodableActionContainerTests extends SwiftCodableActionContainerTests {
   override lazy val swiftContainerImageName = "action-swift-v4.1"
   override lazy val swiftBinaryName = "tests/dat/build/swift4.1/HelloSwift4Codable.zip"
+
+  // TODO
+  // swift 4.2 exceptions executable exiting doesn't return error from web proxy or ends container
+  // the action times out
+  it should "return some error on action error" in {
+    val (out, err) = withActionContainer() { c =>
+      val code = """
+                   | // You need an indirection, or swiftc detects the div/0
+                   | // at compile-time. Smart.
+                   | func div(x: Int, y: Int) -> Int {
+                   |    return x/y
+                   | }
+                   | struct Result: Codable{
+                   |    let divBy0: Int?
+                   | }
+                   | func main(respondWith: (Result?, Error?) -> Void) -> Void {
+                   |    respondWith(Result(divBy0: div(x:5, y:0)), nil)
+                   | }
+                 """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runCode should be(502)
+
+      runRes shouldBe defined
+      runRes.get.fields.get("error") shouldBe defined
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        e should not be empty
+    })
+  }
 }
diff --git a/tests/src/test/scala/runtime/actionContainers/Swift42ActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/Swift42ActionContainerTests.scala
new file mode 100644
index 0000000..5a3c395
--- /dev/null
+++ b/tests/src/test/scala/runtime/actionContainers/Swift42ActionContainerTests.scala
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package runtime.actionContainers
+
+import java.io.File
+
+import actionContainers.ResourceHelpers
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+import spray.json.{JsObject, JsString}
+
+@RunWith(classOf[JUnitRunner])
+class Swift42ActionContainerTests extends SwiftActionContainerTests {
+  override lazy val swiftContainerImageName = "action-swift-v4.2"
+  override lazy val swiftBinaryName = "tests/dat/build/swift4.2/HelloSwift4.zip"
+  lazy val partyCompile = "tests/dat/build/swift4.2/SwiftyRequest.zip"
+  lazy val partyCompileCodable = "tests/dat/build/swift4.2/SwiftyRequestCodable.zip"
+
+  val httpCode = """
+                   | import Dispatch
+                   | func main(args:[String: Any]) -> [String:Any] {
+                   |     var resp :[String:Any] = ["error":"getUrl failed"]
+                   |     guard let urlStr = args["getUrl"] as? String else {
+                   |         return ["error":"getUrl not found in action input"]
+                   |     }
+                   |     guard let url = URL(string: urlStr) else {
+                   |         return ["error":"invalid url string \(urlStr)"]
+                   |     }
+                   |     let request = URLRequest(url: url)
+                   |     let session = URLSession(configuration: .default)
+                   |     let semaphore = DispatchSemaphore(value: 0)
+                   |     let task = session.dataTask(with: request, completionHandler: {data, response, error -> Void in
+                   |         print("done with http request")
+                   |         if let error = error {
+                   |             print("There was an error \(error)")
+                   |         } else if let data = data,
+                   |             let response = response as? HTTPURLResponse,
+                   |             response.statusCode == 200 {
+                   |             do {
+                   |                 let respJson = try JSONSerialization.jsonObject(with: data)
+                   |                 if respJson is [String:Any] {
+                   |                     resp = respJson as! [String:Any]
+                   |                 } else {
+                   |                     resp = ["error":"Response from server is not a dictionary"]
+                   |                 }
+                   |             } catch {
+                   |                 resp = ["error":"Error creating json from response: \(error)"]
+                   |             }
+                   |         }
+                   |         semaphore.signal()
+                   |     })
+                   |     task.resume()
+                   |     _ = semaphore.wait(timeout: .distantFuture)
+                   |     return resp
+                   | }
+                 """.stripMargin
+
+  it should "support ability to use 3rd party packages like SwiftyRequest" in {
+    val zip = new File(partyCompile).toPath
+    val code = ResourceHelpers.readAsBase64(zip)
+
+    val (out, err) = withActionContainer() { c =>
+      val (initCode, initRes) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val args = JsObject("message" -> (JsString("serverless")))
+      val (runCode, runRes) = c.run(runPayload(args))
+
+      runCode should be(200)
+      val json = runRes.get.fields.get("json")
+      json shouldBe Some(args)
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        e shouldBe empty
+    })
+  }
+
+  it should "support ability to use escaping completion in Codable" in {
+    val zip = new File(partyCompileCodable).toPath
+    val code = ResourceHelpers.readAsBase64(zip)
+
+    val (out, err) = withActionContainer() { c =>
+      val (initCode, initRes) = c.init(initPayload(code, main = "mainCodable"))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+
+      runCode should be(200)
+      runRes.get.fields.get("greeting") shouldBe Some(JsString("success"))
+
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        if (enforceEmptyOutputStream) o shouldBe empty
+        e shouldBe empty
+    })
+  }
+
+}
diff --git a/tests/src/test/scala/runtime/actionContainers/Swift42CodableActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/Swift42CodableActionContainerTests.scala
new file mode 100644
index 0000000..0e721fc
--- /dev/null
+++ b/tests/src/test/scala/runtime/actionContainers/Swift42CodableActionContainerTests.scala
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package runtime.actionContainers
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+@RunWith(classOf[JUnitRunner])
+class Swift42CodableActionContainerTests extends SwiftCodableActionContainerTests {
+  override lazy val swiftContainerImageName = "action-swift-v4.2"
+  override lazy val swiftBinaryName = "tests/dat/build/swift4.2/HelloSwift4Codable.zip"
+}
diff --git a/tests/src/test/scala/runtime/actionContainers/SwiftActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/SwiftActionContainerTests.scala
index ecc5f41..1041af0 100644
--- a/tests/src/test/scala/runtime/actionContainers/SwiftActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/SwiftActionContainerTests.scala
@@ -144,54 +144,6 @@ abstract class SwiftActionContainerTests extends BasicActionRunnerTests with Wsk
       """.stripMargin)
   }
 
-  it should "return some error on action error" in {
-    val (out, err) = withActionContainer() { c =>
-      val code = """
-                   | // You need an indirection, or swiftc detects the div/0
-                   | // at compile-time. Smart.
-                   | func div(x: Int, y: Int) -> Int {
-                   |     return x/y
-                   | }
-                   | func main(args: [String: Any]) -> [String: Any] {
-                   |     return [ "divBy0": div(x:5, y:0) ]
-                   | }
-                 """.stripMargin
-
-      val (initCode, _) = c.init(initPayload(code))
-      initCode should be(200)
-
-      val (runCode, runRes) = c.run(runPayload(JsObject()))
-      runCode should be(502)
-
-      runRes shouldBe defined
-      runRes.get.fields.get("error") shouldBe defined
-    }
-
-    checkStreams(out, err, {
-      case (o, e) =>
-        if (enforceEmptyOutputStream) o shouldBe empty
-        if (enforceEmptyOutputStream) e shouldBe empty
-    })
-  }
-
-  it should "log compilation errors" in {
-    val (out, err) = withActionContainer() { c =>
-      val code = """
-                   | 10 PRINT "Hello!"
-                   | 20 GOTO 10
-                 """.stripMargin
-
-      val (initCode, _) = c.init(initPayload(code))
-      initCode should not be (200)
-    }
-
-    checkStreams(out, err, {
-      case (o, e) =>
-        if (enforceEmptyOutputStream) o shouldBe empty
-        e.toLowerCase should include("error")
-    })
-  }
-
   it should "support application errors" in {
     val (out, err) = withActionContainer() { c =>
       val code = """
diff --git a/tests/src/test/scala/runtime/actionContainers/SwiftCodableActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/SwiftCodableActionContainerTests.scala
index a2cb482..d015949 100644
--- a/tests/src/test/scala/runtime/actionContainers/SwiftCodableActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/SwiftCodableActionContainerTests.scala
@@ -200,39 +200,6 @@ abstract class SwiftCodableActionContainerTests extends BasicActionRunnerTests w
     })
   }
 
-  it should "return some error on action error" in {
-    val (out, err) = withActionContainer() { c =>
-      val code = """
-                   | // You need an indirection, or swiftc detects the div/0
-                   | // at compile-time. Smart.
-                   | func div(x: Int, y: Int) -> Int {
-                   |    return x/y
-                   | }
-                   | struct Result: Codable{
-                   |    let divBy0: Int?
-                   | }
-                   | func main(respondWith: (Result?, Error?) -> Void) -> Void {
-                   |    respondWith(Result(divBy0: div(x:5, y:0)), nil)
-                   | }
-                 """.stripMargin
-
-      val (initCode, _) = c.init(initPayload(code))
-      initCode should be(200)
-
-      val (runCode, runRes) = c.run(runPayload(JsObject()))
-      runCode should be(502)
-
-      runRes shouldBe defined
-      runRes.get.fields.get("error") shouldBe defined
-    }
-
-    checkStreams(out, err, {
-      case (o, e) =>
-        if (enforceEmptyOutputStream) o shouldBe empty
-        e should not be empty
-    })
-  }
-
   it should "support application errors" in {
     val (out, err) = withActionContainer() { c =>
       val code = """
diff --git a/tests/src/test/scala/runtime/sdk/Swift42SDKTests.scala b/tests/src/test/scala/runtime/sdk/Swift42SDKTests.scala
new file mode 100644
index 0000000..06402ee
--- /dev/null
+++ b/tests/src/test/scala/runtime/sdk/Swift42SDKTests.scala
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package runtime.sdk
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+@RunWith(classOf[JUnitRunner])
+class Swift42SDKTests extends SwiftSDKTests {
+  override lazy val actionKind = "swift:4.2"
+}
diff --git a/tools/travis/build.sh b/tools/travis/build.sh
index b8ac9ad..b8a18c4 100755
--- a/tools/travis/build.sh
+++ b/tools/travis/build.sh
@@ -46,8 +46,14 @@ docker tag openwhisk/nodejs6action nodejs6action
 
 TERM=dumb ./gradlew install
 
+# install new version docker
+curl -fsSL https://get.docker.com -o get-docker.sh
+sudo sh get-docker.sh
+docker version
+
 # Build runtime
 cd $ROOTDIR
 TERM=dumb ./gradlew \
 :core:swift41Action:distDocker \
+:core:swift42Action:distDocker \
 -PdockerImagePrefix=${IMAGE_PREFIX}
diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
index 42c2c34..dc25183 100755
--- a/tools/travis/publish.sh
+++ b/tools/travis/publish.sh
@@ -34,6 +34,8 @@ if [ ${RUNTIME_VERSION} == "3.1.1" ]; then
   RUNTIME="swift3.1.1Action"
 elif [ ${RUNTIME_VERSION} == "4.1" ]; then
   RUNTIME="swift41Action"
+elif [ ${RUNTIME_VERSION} == "4.2" ]; then
+  RUNTIME="swift42Action"
 fi
 
 if [[ ! -z ${DOCKER_USER} ]] && [[ ! -z ${DOCKER_PASSWORD} ]]; then
@@ -46,4 +48,15 @@ TERM=dumb ./gradlew \
 -PdockerRegistry=docker.io \
 -PdockerImagePrefix=${IMAGE_PREFIX} \
 -PdockerImageTag=${IMAGE_TAG}
+
+  # if doing latest also push a tag with the hash commit
+  if [ ${IMAGE_TAG} == "latest" ]; then
+  SHORT_COMMIT=`git rev-parse --short HEAD`
+  TERM=dumb ./gradlew \
+  :core:${RUNTIME}:distDocker \
+  -PdockerRegistry=docker.io \
+  -PdockerImagePrefix=${IMAGE_PREFIX} \
+  -PdockerImageTag=${SHORT_COMMIT}
+  fi
+
 fi


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services