You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by cs...@apache.org on 2019/01/08 02:33:06 UTC

[incubator-openwhisk-runtime-swift] 02/02: update compiler and added tests

This is an automated email from the ASF dual-hosted git repository.

csantanapr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-runtime-swift.git

commit f8709160cd07e9ca03acfa7a85ce3a9d2ca2528f
Author: Carlos Santana <cs...@apache.org>
AuthorDate: Fri Jan 4 00:58:41 2019 -0500

    update compiler and added tests
---
 .gitignore                                         |   3 +-
 .travis.yml                                        |   2 +-
 README.md                                          |  71 +++++++----
 ansible/environments/local/group_vars/all          |   7 +-
 .../swiftbuild.py.launcher.swift                   |  67 -----------
 .../Dockerfile                                     |  15 ++-
 .../swift42Action/Package.swift                    |  28 +++--
 .../build.gradle                                   |  14 ++-
 core/swift42Action/buildandrecord.py               |  82 +++++++++++++
 .../build.gradle => swift42Action/main.swift}      |   9 +-
 .../swiftbuild.py                                  | 102 +++++++---------
 core/swift42Action/swiftbuild.py.launcher.swift    | 133 +++++++++++++++++++++
 examples/swift-main-single/Makefile                |   8 +-
 examples/swift-main-single/main.swift              |  31 ++++-
 .../swift-main-zip/HelloSwift4/Package.swift       |  28 +++--
 .../swift-main-zip/HelloSwift4/Sources/main.swift  |  10 ++
 examples/swift-main-zip/Makefile                   |  39 ++++++
 settings.gradle                                    |   2 +-
 tests/dat/actions/Makefile                         |  30 +++++
 tests/dat/build.sh                                 |   3 +
 tests/dat/build/swift4.2/HelloSwift4.zip           | Bin 0 -> 2186350 bytes
 tests/dat/build/swift4.2/HelloSwift4Codable.zip    | Bin 0 -> 2190710 bytes
 tests/dat/build/swift4.2/SwiftyRequest.zip         | Bin 0 -> 154371 bytes
 tests/dat/build/swift4.2/SwiftyRequestCodable.zip  | Bin 0 -> 159216 bytes
 .../Swift311ActionContainerTests.scala             |  54 +++++++++
 .../Swift41ActionContainerTests.scala              |  54 +++++++++
 .../Swift41CodableActionContainerTests.scala       |  37 ++++++
 .../Swift42ActionContainerTests.scala              | 118 ++++++++++++++++++
 ...la => Swift42CodableActionContainerTests.scala} |   6 +-
 .../SwiftActionContainerTests.scala                |  48 --------
 .../SwiftCodableActionContainerTests.scala         |  33 -----
 .../test/scala/runtime/sdk/Swift42SDKTests.scala   |  14 ++-
 tools/travis/build.sh                              |   6 +
 tools/travis/publish.sh                            |  13 ++
 34 files changed, 793 insertions(+), 274 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6dc577b..100215f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,4 +76,5 @@ ansible/roles/nginx/files/*cert.pem
 # Makefile artifacts
 test.json
 *.done
-examples/swift-main-single/main.zip
+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/swift421ActionLoop/swiftbuild.py.launcher.swift b/core/swift421ActionLoop/swiftbuild.py.launcher.swift
deleted file mode 100644
index de649ab..0000000
--- a/core/swift421ActionLoop/swiftbuild.py.launcher.swift
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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}"
-    }
-    let buf : [UInt8] = Array(errStr.utf8)
-    write(3, buf, buf.count)
-}
-
-// snippet of code "injected" (wrapper code for invoking traditional main)
-func _run_main(mainFunction: ([String: Any]) -> [String: Any]) -> Void {
-    while let inputStr: String = readLine() {
-        do {
-            let json = inputStr.data(using: .utf8, allowLossyConversion: true)!
-            let parsed = try JSONSerialization.jsonObject(with: json, options: []) as! [String: Any]
-            // TODO put the values in the env
-            let value = parsed["value"] as! [String: Any]
-            let result = mainFunction(value)
-            if JSONSerialization.isValidJSONObject(result) {
-                do {
-                    let jsonData = try JSONSerialization.data(withJSONObject: result, options: [])
-                    var json = [UInt8](jsonData)
-                    json.append(10)
-                    write(3, json, json.count)
-                    fflush(stdout)
-                    fflush(stderr)
-                } 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
-        }
-    }
-}
-
-// snippets of code "injected", dependending on the type of function the developer
-// wants to use traditional vs codable
-
diff --git a/core/swift421ActionLoop/Dockerfile b/core/swift42Action/Dockerfile
similarity index 75%
rename from core/swift421ActionLoop/Dockerfile
rename to core/swift42Action/Dockerfile
index 506da76..e3e018b 100644
--- a/core/swift421ActionLoop/Dockerfile
+++ b/core/swift42Action/Dockerfile
@@ -16,16 +16,16 @@
 #
 FROM openwhisk/actionloop as builder
 
-FROM swift:4.2.1
+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 \
+	&& 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" 
+	LC_ALL="en_US.UTF-8"
 
 RUN mkdir -p /swiftAction
 WORKDIR /swiftAction
@@ -34,6 +34,15 @@ 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/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala b/core/swift42Action/Package.swift
similarity index 67%
copy from tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
copy to core/swift42Action/Package.swift
index cd0a8ba..181e352 100644
--- a/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
+++ b/core/swift42Action/Package.swift
@@ -1,3 +1,6 @@
+// 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
@@ -15,13 +18,20 @@
  * limitations under the License.
  */
 
-package runtime.actionContainers
-
-import org.junit.runner.RunWith
-import org.scalatest.junit.JUnitRunner
+import PackageDescription
 
-@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"
-}
+let package = Package(
+    name: "Action",
+    products: [
+      .executable(
+        name: "Action",
+        targets:  ["Action"]
+      )
+    ],
+    targets: [
+      .target(
+        name: "Action",
+        path: "."
+      )
+    ]
+)
diff --git a/core/swift421ActionLoop/build.gradle b/core/swift42Action/build.gradle
similarity index 75%
copy from core/swift421ActionLoop/build.gradle
copy to core/swift42Action/build.gradle
index d9bb28f..117edc2 100755
--- a/core/swift421ActionLoop/build.gradle
+++ b/core/swift42Action/build.gradle
@@ -15,5 +15,17 @@
  * limitations under the License.
  */
 
-ext.dockerImageName = 'actionloop-swift-v4.2.1'
+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/swift421ActionLoop/build.gradle b/core/swift42Action/main.swift
old mode 100755
new mode 100644
similarity index 79%
rename from core/swift421ActionLoop/build.gradle
rename to core/swift42Action/main.swift
index d9bb28f..75071a3
--- a/core/swift421ActionLoop/build.gradle
+++ b/core/swift42Action/main.swift
@@ -15,5 +15,10 @@
  * limitations under the License.
  */
 
-ext.dockerImageName = 'actionloop-swift-v4.2.1'
-apply from: '../../gradle/docker.gradle'
+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/swift421ActionLoop/swiftbuild.py b/core/swift42Action/swiftbuild.py
similarity index 54%
rename from core/swift421ActionLoop/swiftbuild.py
rename to core/swift42Action/swiftbuild.py
index 49ec29d..9b40903 100755
--- a/core/swift421ActionLoop/swiftbuild.py
+++ b/core/swift42Action/swiftbuild.py
@@ -26,61 +26,35 @@ import codecs
 import subprocess
 from io import StringIO
 
-package_swift = """// swift-tools-version:4.2
-import PackageDescription
-
-let package = Package(
-    name: "exec",
-    dependencies: [],
-    targets: [
-      .target(
-        name: "exec",
-        dependencies: [])
-    ]
-)
-"""
-output = StringIO()
-
 def eprint(*args, **kwargs):
-    print(*args, file=output, **kwargs)
+    print(*args, file=sys.stderr, **kwargs)
 
 def sources(launcher, source_dir, main):
-    # create Packages.swift
-    packagefile = "%s/Package.swift" % source_dir
-    if not os.path.isfile(packagefile):
-        with codecs.open(packagefile, 'w', 'utf-8') as s:
-            s.write(package_swift)
-
-    # create Sources/Action dir
-    actiondir = "%s/Sources/exec" % source_dir
-    if not os.path.isdir(actiondir):
-        os.makedirs(actiondir, mode=0o755)
-
-    # copy the exec to exec.go
-    # also check if it has a main in it
-    src = "%s/exec" % source_dir
-    dst = "%s/exec.swift" % actiondir
-    if os.path.isfile(src):
-        with codecs.open(src, 'r', 'utf-8') as s:
-            with codecs.open(dst, 'w', 'utf-8') as d:
-                body = s.read()
-                d.write(body)
-
+    actiondir = "%s/Sources" % source_dir
     # copy the launcher fixing the main
     dst = "%s/main.swift" % actiondir
-    with codecs.open(dst, 'w', 'utf-8') as d:
+    with codecs.open(dst, 'a', 'utf-8') as d:
         with codecs.open(launcher, 'r', 'utf-8') as e:
             code = e.read()
-            code += "_run_main(mainFunction: %s)\n" % main
+            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, extra_args=[]):
-    base_args =  ["swift", "build", "--package-path", dir,  "-c", "release"]
+def swift_build(dir, buildcmd):
     # compile...
     env = {
       "PATH": os.environ["PATH"]
     }
-    p = subprocess.Popen(base_args+extra_args,
+    p = subprocess.Popen(buildcmd,
         stdout=subprocess.PIPE,
         stderr=subprocess.PIPE,
         cwd=dir,
@@ -95,25 +69,20 @@ def swift_build(dir, extra_args=[]):
         e = e.decode('utf-8')
     return p.returncode, o, e
 
-def build(source_dir, target_file):
-    r, o, e = swift_build(source_dir)
-    if e: eprint(e)
-    if o: eprint(o)
+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(output.getvalue())
+        print(e)
+        print(o)
+        print(r)
         return
 
-    r, o, e = swift_build(source_dir, ["--show-bin-path"])
-    if e: eprint(e)
-    if r != 0:
-        print(output.getvalue())
-        return
-
-    bin_file = "%s/exec" % o.strip()
+    bin_file = "%s/.build/release/Action" % source_dir
     os.rename(bin_file, target_file)
     if not os.path.isfile(target_file):
-        eprint("failed %s -> %s" % (bin_file, target_file))
-        print(output.getvalue())
+        print("failed %s -> %s" % (bin_file, target_file))
         return
 
 
@@ -126,8 +95,25 @@ def main(argv):
     source_dir = os.path.abspath(argv[2])
     target = os.path.abspath("%s/exec" % argv[3])
     launch = os.path.abspath(argv[0]+".launcher.swift")
-    sources(launch, source_dir, main)
-    build(source_dir, target)
+
+    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
index 0545f1b..83950ca 100644
--- a/examples/swift-main-single/Makefile
+++ b/examples/swift-main-single/Makefile
@@ -1,7 +1,7 @@
-OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-swift-v4.2.1
-OW_COMPILER?=$(OW_USER)/actionloop-swift-v4.2.1
-WSK?=wsk
+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
diff --git a/examples/swift-main-single/main.swift b/examples/swift-main-single/main.swift
index 7d8521e..9a7aaf8 100644
--- a/examples/swift-main-single/main.swift
+++ b/examples/swift-main-single/main.swift
@@ -19,6 +19,35 @@ func main(args: [String:Any]) -> [String:Any] {
     if let name = args["name"] as? String {
         return [ "greeting" : "Hello \(name)!" ]
     } else {
-        return [ "greeting" : "Hello swif4!" ]
+        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/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala b/examples/swift-main-zip/HelloSwift4/Package.swift
similarity index 67%
copy from tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
copy to examples/swift-main-zip/HelloSwift4/Package.swift
index cd0a8ba..181e352 100644
--- a/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
+++ b/examples/swift-main-zip/HelloSwift4/Package.swift
@@ -1,3 +1,6 @@
+// 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
@@ -15,13 +18,20 @@
  * limitations under the License.
  */
 
-package runtime.actionContainers
-
-import org.junit.runner.RunWith
-import org.scalatest.junit.JUnitRunner
+import PackageDescription
 
-@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"
-}
+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 4627e15..7b18e3c 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -21,7 +21,7 @@ include 'core:swift3.1.1Action'
 
 include 'core:swift41Action'
 
-include 'core:swift421ActionLoop'
+include 'core:swift42Action'
 
 rootProject.name = 'runtime-swift'
 
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/Swift41CodableActionContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/Swift42CodableActionContainerTests.scala
similarity index 83%
copy from tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
copy to tests/src/test/scala/runtime/actionContainers/Swift42CodableActionContainerTests.scala
index cd0a8ba..0e721fc 100644
--- a/tests/src/test/scala/runtime/actionContainers/Swift41CodableActionContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/Swift42CodableActionContainerTests.scala
@@ -21,7 +21,7 @@ import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
 @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"
+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/examples/swift-main-single/main.swift b/tests/src/test/scala/runtime/sdk/Swift42SDKTests.scala
similarity index 78%
copy from examples/swift-main-single/main.swift
copy to tests/src/test/scala/runtime/sdk/Swift42SDKTests.scala
index 7d8521e..06402ee 100644
--- a/examples/swift-main-single/main.swift
+++ b/tests/src/test/scala/runtime/sdk/Swift42SDKTests.scala
@@ -15,10 +15,12 @@
  * 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!" ]
-    }
+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