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 2017/06/26 23:33:29 UTC

[incubator-openwhisk] branch master updated: Add Swift 3.1.1 as a kind (#2120)

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.git


The following commit(s) were added to refs/heads/master by this push:
     new db21c08  Add Swift 3.1.1 as a kind (#2120)
db21c08 is described below

commit db21c089dac0e7bf87fbf648a83d50ef974cf673
Author: Paul Castro <ca...@us.ibm.com>
AuthorDate: Mon Jun 26 19:33:27 2017 -0400

    Add Swift 3.1.1 as a kind (#2120)
    
    * Experimental branch for 2079, uses ibm swift ubuntu image for 3.1
    
    * Fixes issue #2079, add Swift 3.1.1 runtime kind, update Swift dependencies for Watson SDK, KituraNet, SwiftyJson
    
    * add apache license
    
    * Fix swift311 location and catch docker brake
    
    The location of the swift binary for 311 is now in /usr/bin/swift
    Need to catch docker errors when building by usig && instead of ;
    
    * new zip for new swift311 runtime
---
 ansible/group_vars/all                             |   5 +-
 ansible/roles/invoker/tasks/deploy.yml             |   1 +
 core/swift3.1.1Action/Dockerfile                   |  30 ++++++++
 core/swift3.1.1Action/build.gradle                 |  41 +++++++++++
 core/swift3.1.1Action/buildandrecord.py            |  77 +++++++++++++++++++++
 core/swift3.1.1Action/spm-build/Package.swift      |  27 ++++++++
 core/swift3Action/Dockerfile                       |   4 +-
 docs/actions.md                                    |   2 +-
 docs/reference.md                                  |  16 +++++
 settings.gradle                                    |   1 +
 tests/build.gradle                                 |   1 +
 tests/dat/actions/helloSwift.zip                   | Bin 748064 -> 0 bytes
 tests/dat/actions/helloSwift3.zip                  | Bin 0 -> 741267 bytes
 tests/dat/actions/helloSwift311.zip                | Bin 0 -> 1792469 bytes
 .../scala/actionContainers/ActionContainer.scala   |   4 +-
 .../Swift311ActionContainerTests.scala             |  45 ++++++++++++
 ...ests.scala => Swift3ActionContainerTests.scala} |  24 ++++---
 ...wiftTests.scala => WskBasicSwift311Tests.scala} |  13 +---
 ...Tests.scala => WskBasicSwift3DefaultTest.scala} |  23 +-----
 ...cSwiftTests.scala => WskBasicSwift3Tests.scala} |  23 +-----
 ...ftTests.scala => WskUnicodeSwift311Tests.scala} |   4 +-
 ...wiftTests.scala => WskUnicodeSwift3Tests.scala} |   2 +-
 .../core/cli/test/Swift311Tests.scala}             |  15 ++--
 .../test/{SwiftTests.scala => Swift3Tests.scala}   |  36 ++--------
 tools/build/redo                                   |   5 ++
 25 files changed, 287 insertions(+), 112 deletions(-)

diff --git a/ansible/group_vars/all b/ansible/group_vars/all
index c4f438b..344462b 100644
--- a/ansible/group_vars/all
+++ b/ansible/group_vars/all
@@ -62,6 +62,9 @@ runtimesManifest:
       default: true
       image:
         name: "swift3action"
+    - kind: "swift:3.1.1"
+      image:
+        name: "action-swift-v3.1.1"
     java:
     - kind: "java"
       attached:
@@ -230,4 +233,4 @@ catalog_repos:
     # Set the local location as the same level as openwhisk home, but it can be changed.
     location: "{{ openwhisk_home }}/../openwhisk-catalog"
     version: "HEAD"
-    repo_update: "no"
+    repo_update: "no"
\ No newline at end of file
diff --git a/ansible/roles/invoker/tasks/deploy.yml b/ansible/roles/invoker/tasks/deploy.yml
index 73e32f7..199b1cc 100644
--- a/ansible/roles/invoker/tasks/deploy.yml
+++ b/ansible/roles/invoker/tasks/deploy.yml
@@ -12,6 +12,7 @@
     - '{{ docker_image_prefix }}/python2action'
     - '{{ docker_image_prefix }}/python3action'
     - '{{ docker_image_prefix }}/swift3action'
+    - '{{ docker_image_prefix }}/action-swift-v3.1.1'
     - '{{ docker_image_prefix }}/java8action'
   when: docker_registry != ""
   retries: 3
diff --git a/core/swift3.1.1Action/Dockerfile b/core/swift3.1.1Action/Dockerfile
new file mode 100755
index 0000000..352767f
--- /dev/null
+++ b/core/swift3.1.1Action/Dockerfile
@@ -0,0 +1,30 @@
+# Dockerfile for swift actions, overrides and extends ActionRunner from actionProxy
+# This Dockerfile is partially based on: https://github.com/IBM-Swift/swift-ubuntu-docker/blob/master/swift-development/Dockerfile
+FROM ibmcom/swift-ubuntu:3.1.1
+
+# Set WORKDIR
+WORKDIR /
+
+# Upgrade and install basic Python dependencies
+RUN apt-get -y update \
+ && apt-get -y install --fix-missing python2.7 python-gevent python-flask zip
+
+# Add the action proxy
+RUN mkdir -p /actionProxy
+ADD actionproxy.py /actionProxy
+
+# Add files needed to build and run action
+RUN mkdir -p /swift3Action
+ADD epilogue.swift /swift3Action
+ADD buildandrecord.py /swift3Action
+ADD swift3runner.py /swift3Action
+ADD spm-build /swift3Action/spm-build
+
+
+# Build kitura net
+RUN touch /swift3Action/spm-build/main.swift
+RUN python /swift3Action/buildandrecord.py && rm /swift3Action/spm-build/.build/release/Action
+#RUN cd /swift3Action/spm-build; swift build -v -c release; rm /swift3Action/spm-build/.build/release/Action
+ENV FLASK_PROXY_PORT 8080
+
+CMD ["/bin/bash", "-c", "cd /swift3Action && PYTHONIOENCODING='utf-8' python -u swift3runner.py"]
\ No newline at end of file
diff --git a/core/swift3.1.1Action/build.gradle b/core/swift3.1.1Action/build.gradle
new file mode 100755
index 0000000..d26283e
--- /dev/null
+++ b/core/swift3.1.1Action/build.gradle
@@ -0,0 +1,41 @@
+ext.dockerImageName = 'action-swift-v3.1.1'
+apply from: '../../gradle/docker.gradle'
+distDocker.dependsOn 'copyProxy'
+distDocker.dependsOn 'copyEpilogue'
+distDocker.dependsOn 'copySwiftRunner'
+distDocker.dependsOn 'copyWhisk'
+distDocker.dependsOn 'copyWhiskJsonUtils'
+distDocker.finalizedBy('cleanup')
+
+task copyProxy(type: Copy) {
+    from '../actionProxy/actionproxy.py'
+    into './actionproxy.py'
+}
+
+task copyEpilogue(type: Copy) {
+    from '../swift3Action/epilogue.swift'
+    into '.'
+}
+
+task copySwiftRunner(type: Copy) {
+    from '../swift3Action/swift3runner.py'
+    into '.'
+}
+
+task copyWhisk(type: Copy) {
+    from '../swift3Action/spm-build/_Whisk.swift'
+    into './spm-build'
+}
+
+task copyWhiskJsonUtils(type: Copy) {
+    from '../swift3Action/spm-build/_WhiskJSONUtils.swift'
+    into './spm-build'
+}
+
+task cleanup(type: Delete) {
+    delete 'actionproxy.py'
+    delete 'epilogue.swift'
+    delete 'swift3runner.py'
+    delete 'spm-build/_Whisk.swift'
+    delete 'spm-build/_WhiskJSONUtils.swift'
+}
diff --git a/core/swift3.1.1Action/buildandrecord.py b/core/swift3.1.1Action/buildandrecord.py
new file mode 100755
index 0000000..6f0ab75
--- /dev/null
+++ b/core/swift3.1.1Action/buildandrecord.py
@@ -0,0 +1,77 @@
+"""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 -Xlinker '-rpath=$ORIGIN' '-L/swift3Action/spm-build/.build/release' -o '/swift3Action/spm-build/.build/release/Action'"
+GENERATED_BUILD_SCRIPT = "/swift3Action/spm-build/swiftbuildandlink.sh"
+SPM_DIRECTORY = "/swift3Action/spm-build"
+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:
+    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, "a") as buildScript:
+        buildScript.write("#!/bin/bash\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("echo \"Linking\"\n")
+        buildScript.write("%s\n" % linkCommand)
+        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/swift3.1.1Action/spm-build/Package.swift b/core/swift3.1.1Action/spm-build/Package.swift
new file mode 100755
index 0000000..a5e9e52
--- /dev/null
+++ b/core/swift3.1.1Action/spm-build/Package.swift
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015-2016 IBM Corporation
+ *
+ * Licensed 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",
+        dependencies: [
+            .Package(url: "https://github.com/IBM-Swift/CCurl.git", "0.2.3"),
+            .Package(url: "https://github.com/IBM-Swift/Kitura-net.git", "1.7.10"),
+            .Package(url: "https://github.com/IBM-Swift/SwiftyJSON.git", "15.0.1"),
+            .Package(url: "https://github.com/watson-developer-cloud/swift-sdk.git", "0.16.0")
+        ]
+)
diff --git a/core/swift3Action/Dockerfile b/core/swift3Action/Dockerfile
index 2f2fb4b..aa766d4 100644
--- a/core/swift3Action/Dockerfile
+++ b/core/swift3Action/Dockerfile
@@ -61,8 +61,8 @@ ADD spm-build /swift3Action/spm-build
 
 # Build kitura net
 RUN touch /swift3Action/spm-build/main.swift
-RUN python /swift3Action/buildandrecord.py; rm /swift3Action/spm-build/.build/release/Action
+RUN python /swift3Action/buildandrecord.py && rm /swift3Action/spm-build/.build/release/Action
 #RUN cd /swift3Action/spm-build; swift build -c release; rm /swift3Action/spm-build/.build/release/Action
 ENV FLASK_PROXY_PORT 8080
 
-CMD ["/bin/bash", "-c", "cd /swift3Action && PYTHONIOENCODING='utf-8' python -u swift3runner.py"]
+CMD ["/bin/bash", "-c", "cd /swift3Action && PYTHONIOENCODING='utf-8' python -u swift3runner.py"]
\ No newline at end of file
diff --git a/docs/actions.md b/docs/actions.md
index e566de7..6cbab38 100644
--- a/docs/actions.md
+++ b/docs/actions.md
@@ -680,7 +680,7 @@ docker run --rm -it -v "$(pwd):/owexec" openwhisk/swift3action bash
 This has created hello.zip in the same directory as hello.swift. 
 -Upload it to OpenWhisk with the action name helloSwifty:
   ```
-  wsk action update helloSwiftly hello.zip --kind swift:3
+  wsk action update helloSwiftly hello.zip --kind swift:3.1.1
   ```
 
 - To check how much faster it is, run 
diff --git a/docs/reference.md b/docs/reference.md
index 85a2a19..686cc2f 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -354,6 +354,22 @@ Python 2 actions are executed using Python 2.7.12. This is the default runtime f
 - Werkzeug v0.12
 - zope.interface v4.3.3
 
+## Swift actions
+
+### Swift 3
+Swift 3 actions are executed using Swift 3.0.2  `--kind swift:3` or Swift 3.1.1 `--kind swift:3.1.1`, respectively.  The default `--kind swift:default` is Swift 3.0.2.
+
+Swift 3.0.2 actions can use the following packages:
+- KituraNet version 1.0.1, https://github.com/IBM-Swift/Kitura-net
+- SwiftyJSON version 14.2.0, https://github.com/IBM-Swift/SwiftyJSON
+- IBM Swift Watson SDK version 0.4.1, https://github.com/IBM-Swift/swift-watson-sdk
+
+Swift 3.1.1 actions can use the following packages:
+- KituraNet version 1.7.6, https://github.com/IBM-Swift/Kitura-net
+- SwiftyJSON version 15.0.1, https://github.com/IBM-Swift/SwiftyJSON
+- Watson Developer Cloud SDK version 0.16.0, https://github.com/watson-developer-cloud/swift-sdk
+
+
 ## Docker actions
 
 Docker actions run a user-supplied binary in a Docker container. The binary runs in a Docker image based on [python:3.6.1-alpine](https://hub.docker.com/r/library/python), so the binary must be compatible with this distribution.
diff --git a/settings.gradle b/settings.gradle
index 1955feb..868fcd7 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -8,6 +8,7 @@ include 'core:actionProxy'
 include 'core:pythonAction'
 include 'core:python2Action'
 include 'core:swift3Action'
+include 'core:swift3.1.1Action'
 include 'core:javaAction'
 
 include 'tools:cli'
diff --git a/tests/build.gradle b/tests/build.gradle
index 21ab9f8..f80e47e 100644
--- a/tests/build.gradle
+++ b/tests/build.gradle
@@ -32,6 +32,7 @@ test.dependsOn([
     ':core:python2Action:distDocker',
     ':core:javaAction:distDocker',
     ':core:swift3Action:distDocker',
+    ':core:swift3.1.1Action:distDocker',
     ':sdk:docker:distDocker',
     ':tests:dat:blackbox:badaction:distDocker',
     ':tests:dat:blackbox:badproxy:distDocker'
diff --git a/tests/dat/actions/helloSwift.zip b/tests/dat/actions/helloSwift.zip
deleted file mode 100644
index 0134c96..0000000
Binary files a/tests/dat/actions/helloSwift.zip and /dev/null differ
diff --git a/tests/dat/actions/helloSwift3.zip b/tests/dat/actions/helloSwift3.zip
new file mode 100644
index 0000000..356fcdb
Binary files /dev/null and b/tests/dat/actions/helloSwift3.zip differ
diff --git a/tests/dat/actions/helloSwift311.zip b/tests/dat/actions/helloSwift311.zip
new file mode 100644
index 0000000..5eac158
Binary files /dev/null and b/tests/dat/actions/helloSwift311.zip differ
diff --git a/tests/src/test/scala/actionContainers/ActionContainer.scala b/tests/src/test/scala/actionContainers/ActionContainer.scala
index 4f00e7c..f74f3c4 100644
--- a/tests/src/test/scala/actionContainers/ActionContainer.scala
+++ b/tests/src/test/scala/actionContainers/ActionContainer.scala
@@ -178,11 +178,11 @@ object ActionContainer {
         val f = for (
             entity <- Marshal(content).to[MessageEntity];
             request = HttpRequest(method = HttpMethods.POST, uri = uri, entity = entity);
-            response <- AkkaHttpUtils.singleRequest(request, 60.seconds, retryOnTCPErrors = true);
+            response <- AkkaHttpUtils.singleRequest(request, 90.seconds, retryOnTCPErrors = true);
             responseBody <- Unmarshal(response.entity).to[String]
         ) yield (response.status.intValue, Try(responseBody.parseJson.asJsObject).toOption)
 
-        Await.result(f, 1.minute)
+        Await.result(f, 90.seconds)
     }
 
     private class ActionContainerImpl() extends ActionContainer {
diff --git a/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala
new file mode 100644
index 0000000..48009de
--- /dev/null
+++ b/tests/src/test/scala/actionContainers/Swift311ActionContainerTests.scala
@@ -0,0 +1,45 @@
+/*
+ * 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 actionContainers
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+@RunWith(classOf[JUnitRunner])
+class Swift311ActionContainerTests extends Swift3ActionContainerTests {
+    override lazy val swiftContainerImageName = "action-swift-v3.1.1"
+
+    override lazy val watsonCode = """
+                | import AlchemyDataNewsV1
+                | import ConversationV1
+                | import DiscoveryV1
+                | import DocumentConversionV1
+                | import NaturalLanguageClassifierV1
+                | import NaturalLanguageUnderstandingV1
+                | import PersonalityInsightsV3
+                | import RetrieveAndRankV1
+                | import ToneAnalyzerV3
+                | import TradeoffAnalyticsV1
+                | import VisualRecognitionV3
+                |
+                | func main(args: [String:Any]) -> [String:Any] {
+                |     return ["message": "I compiled and was able to import Watson SDKs"]
+                | }
+            """.stripMargin
+    override lazy val swiftBinaryName = "helloSwift311.zip"
+}
diff --git a/tests/src/test/scala/actionContainers/SwiftActionContainerTests.scala b/tests/src/test/scala/actionContainers/Swift3ActionContainerTests.scala
similarity index 97%
rename from tests/src/test/scala/actionContainers/SwiftActionContainerTests.scala
rename to tests/src/test/scala/actionContainers/Swift3ActionContainerTests.scala
index c07ef75..6238acf 100644
--- a/tests/src/test/scala/actionContainers/SwiftActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Swift3ActionContainerTests.scala
@@ -29,7 +29,7 @@ import spray.json.JsString
 import common.TestUtils
 
 @RunWith(classOf[JUnitRunner])
-class SwiftActionContainerTests extends BasicActionRunnerTests with WskActorSystem {
+class Swift3ActionContainerTests extends BasicActionRunnerTests with WskActorSystem {
 
     // note: "out" will likely not be empty in some swift build as the compiler
     // prints status messages and there doesn't seem to be a way to quiet them
@@ -78,6 +78,16 @@ class SwiftActionContainerTests extends BasicActionRunnerTests with WskActorSyst
                 |     return [ "divBy0": div(x:5, y:0) ]
                 | }
             """.stripMargin
+    lazy val watsonCode ="""
+                | import RestKit
+                | import WeatherCompanyData
+                | import AlchemyVision
+                |
+                | func main(args: [String:Any]) -> [String:Any] {
+                |     return ["message": "I compiled and was able to import Watson SDKs"]
+                | }
+            """.stripMargin
+    lazy val swiftBinaryName = "helloSwift3.zip"
 
     // Helpers specific to swift actions
     override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = {
@@ -238,7 +248,7 @@ class SwiftActionContainerTests extends BasicActionRunnerTests with WskActorSyst
     }
 
     it should "support pre-compiled binary in a zip file" in {
-        val zip = new File(TestUtils.getTestActionFilename("helloSwift.zip")).toPath
+        val zip = new File(TestUtils.getTestActionFilename(swiftBinaryName)).toPath
         val code = ResourceHelpers.readAsBase64(zip)
 
         val (out, err) = withActionContainer() { c =>
@@ -331,15 +341,7 @@ class SwiftActionContainerTests extends BasicActionRunnerTests with WskActorSyst
 
     it should "make Watson SDKs available to action authors" in {
         val (out, err) = withActionContainer() { c =>
-            val code = """
-                | import RestKit
-                | import WeatherCompanyData
-                | import AlchemyVision
-                |
-                | func main(args: [String:Any]) -> [String:Any] {
-                |     return ["message": "I compiled and was able to import Watson SDKs"]
-                | }
-            """.stripMargin
+            val code = watsonCode
 
             val (initCode, _) = c.init(initPayload(code))
 
diff --git a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala b/tests/src/test/scala/system/basic/WskBasicSwift311Tests.scala
similarity index 78%
copy from tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
copy to tests/src/test/scala/system/basic/WskBasicSwift311Tests.scala
index 93eee8d..aef9db5 100644
--- a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
+++ b/tests/src/test/scala/system/basic/WskBasicSwift311Tests.scala
@@ -20,16 +20,9 @@ package system.basic
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
-import common.JsHelpers
-import common.WskTestHelpers
-
 @RunWith(classOf[JUnitRunner])
-class WskUnicodeSwiftTests
-    extends WskUnicodeTests
-    with WskTestHelpers
-    with JsHelpers {
-
-    override lazy val actionKind = "swift:3"
-    override lazy val actionSource = "unicode.swift"
+class WskBasicSwift311Tests
+    extends WskBasicSwift3Tests {
 
+    override lazy val currentSwiftDefaultKind = "swift:3.1.1"
 }
diff --git a/tests/src/test/scala/system/basic/WskBasicSwiftTests.scala b/tests/src/test/scala/system/basic/WskBasicSwift3DefaultTest.scala
similarity index 72%
copy from tests/src/test/scala/system/basic/WskBasicSwiftTests.scala
copy to tests/src/test/scala/system/basic/WskBasicSwift3DefaultTest.scala
index 2c6f799..71de8c2 100644
--- a/tests/src/test/scala/system/basic/WskBasicSwiftTests.scala
+++ b/tests/src/test/scala/system/basic/WskBasicSwift3DefaultTest.scala
@@ -29,12 +29,11 @@ import common.WskTestHelpers
 import spray.json.DefaultJsonProtocol.StringJsonFormat
 import spray.json.pimpAny
 import spray.json.pimpString
-import spray.json.JsString
 import common.TestUtils.RunResult
 import spray.json.JsObject
 
 @RunWith(classOf[JUnitRunner])
-class WskBasicSwiftTests
+class WskBasicSwift3DefaultTests
     extends TestHelpers
     with WskTestHelpers
     with JsHelpers {
@@ -42,7 +41,7 @@ class WskBasicSwiftTests
     implicit val wskprops = WskProps()
     val wsk = new Wsk
     val defaultAction = Some(TestUtils.getTestActionFilename("hello.swift"))
-    val currentSwiftDefaultKind = "swift:3"
+    lazy val currentSwiftDefaultKind = "swift:3"
 
     behavior of "Swift runtime"
 
@@ -63,24 +62,6 @@ class WskBasicSwiftTests
             }
     }
 
-    it should "Ensure that Swift actions can have a non-default entrypoint" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "niamSwiftAction"
-            val file = Some(TestUtils.getTestActionFilename("niam.swift"))
-
-            assetHelper.withCleaner(wsk.action, name) {
-                (action, _) =>
-                    action.create(name, file, main = Some("niam"))
-            }
-
-            withActivation(wsk.activation, wsk.action.invoke(name)) {
-                activation =>
-                    val response = activation.response
-                    response.result.get.fields.get("error") shouldBe empty
-                    response.result.get.fields.get("greetings") should be(Some(JsString("Hello from a non-standard entrypoint.")))
-            }
-    }
-
     def convertRunResultToJsObject(result: RunResult): JsObject = {
         val stdout = result.stdout
         val firstNewline = stdout.indexOf("\n")
diff --git a/tests/src/test/scala/system/basic/WskBasicSwiftTests.scala b/tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala
similarity index 74%
rename from tests/src/test/scala/system/basic/WskBasicSwiftTests.scala
rename to tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala
index 2c6f799..5d34f69 100644
--- a/tests/src/test/scala/system/basic/WskBasicSwiftTests.scala
+++ b/tests/src/test/scala/system/basic/WskBasicSwift3Tests.scala
@@ -26,15 +26,13 @@ import common.TestUtils
 import common.Wsk
 import common.WskProps
 import common.WskTestHelpers
-import spray.json.DefaultJsonProtocol.StringJsonFormat
-import spray.json.pimpAny
 import spray.json.pimpString
 import spray.json.JsString
 import common.TestUtils.RunResult
 import spray.json.JsObject
 
 @RunWith(classOf[JUnitRunner])
-class WskBasicSwiftTests
+class WskBasicSwift3Tests
     extends TestHelpers
     with WskTestHelpers
     with JsHelpers {
@@ -42,27 +40,10 @@ class WskBasicSwiftTests
     implicit val wskprops = WskProps()
     val wsk = new Wsk
     val defaultAction = Some(TestUtils.getTestActionFilename("hello.swift"))
-    val currentSwiftDefaultKind = "swift:3"
+    lazy val currentSwiftDefaultKind = "swift:3"
 
     behavior of "Swift runtime"
 
-    it should "Map a kind of swift:default to the current default swift runtime" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "usingDefaultSwiftAlias"
-
-            assetHelper.withCleaner(wsk.action, name) {
-                (action, _) =>
-                    action.create(name, defaultAction, kind = Some("swift:default"))
-            }
-
-            val result = wsk.action.get(name)
-            withPrintOnFailure(result) {
-                () =>
-                    val action = convertRunResultToJsObject(result)
-                    action.getFieldPath("exec", "kind") should be(Some(currentSwiftDefaultKind.toJson))
-            }
-    }
-
     it should "Ensure that Swift actions can have a non-default entrypoint" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "niamSwiftAction"
diff --git a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala b/tests/src/test/scala/system/basic/WskUnicodeSwift311Tests.scala
similarity index 93%
copy from tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
copy to tests/src/test/scala/system/basic/WskUnicodeSwift311Tests.scala
index 93eee8d..5b56d56 100644
--- a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
+++ b/tests/src/test/scala/system/basic/WskUnicodeSwift311Tests.scala
@@ -24,12 +24,12 @@ import common.JsHelpers
 import common.WskTestHelpers
 
 @RunWith(classOf[JUnitRunner])
-class WskUnicodeSwiftTests
+class WskUnicodeSwift311Tests
     extends WskUnicodeTests
     with WskTestHelpers
     with JsHelpers {
 
-    override lazy val actionKind = "swift:3"
+    override lazy val actionKind = "swift:3.1.1"
     override lazy val actionSource = "unicode.swift"
 
 }
diff --git a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala b/tests/src/test/scala/system/basic/WskUnicodeSwift3Tests.scala
similarity index 97%
copy from tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
copy to tests/src/test/scala/system/basic/WskUnicodeSwift3Tests.scala
index 93eee8d..bddc21d 100644
--- a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
+++ b/tests/src/test/scala/system/basic/WskUnicodeSwift3Tests.scala
@@ -24,7 +24,7 @@ import common.JsHelpers
 import common.WskTestHelpers
 
 @RunWith(classOf[JUnitRunner])
-class WskUnicodeSwiftTests
+class WskUnicodeSwift3Tests
     extends WskUnicodeTests
     with WskTestHelpers
     with JsHelpers {
diff --git a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala b/tests/src/test/scala/whisk/core/cli/test/Swift311Tests.scala
similarity index 76%
rename from tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
rename to tests/src/test/scala/whisk/core/cli/test/Swift311Tests.scala
index 93eee8d..1a8bce6 100644
--- a/tests/src/test/scala/system/basic/WskUnicodeSwiftTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/Swift311Tests.scala
@@ -15,21 +15,14 @@
  * limitations under the License.
  */
 
-package system.basic
+package whisk.core.cli.test
 
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
-import common.JsHelpers
-import common.WskTestHelpers
-
 @RunWith(classOf[JUnitRunner])
-class WskUnicodeSwiftTests
-    extends WskUnicodeTests
-    with WskTestHelpers
-    with JsHelpers {
-
-    override lazy val actionKind = "swift:3"
-    override lazy val actionSource = "unicode.swift"
+class Swift311Tests
+    extends Swift3Tests {
 
+    override lazy val runtimeContainer = "swift:3.1.1"
 }
diff --git a/tests/src/test/scala/whisk/core/cli/test/SwiftTests.scala b/tests/src/test/scala/whisk/core/cli/test/Swift3Tests.scala
similarity index 84%
rename from tests/src/test/scala/whisk/core/cli/test/SwiftTests.scala
rename to tests/src/test/scala/whisk/core/cli/test/Swift3Tests.scala
index bb6db50..73a2d6a 100644
--- a/tests/src/test/scala/whisk/core/cli/test/SwiftTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/Swift3Tests.scala
@@ -31,7 +31,7 @@ import spray.json.DefaultJsonProtocol.StringJsonFormat
 import spray.json.pimpAny
 
 @RunWith(classOf[JUnitRunner])
-class SwiftTests
+class Swift3Tests
     extends TestHelpers
     with WskTestHelpers
     with Matchers {
@@ -41,12 +41,14 @@ class SwiftTests
     val expectedDuration = 45 seconds
     val activationPollDuration = 60 seconds
 
+    lazy val runtimeContainer = "swift:3"
+
     behavior of "Swift Actions"
 
     /**
      * Test the Swift "hello world" demo sequence
      */
-    it should "invoke a swift action" in withAssetCleaner(wskprops) {
+    it should "invoke a swift 3 action" in withAssetCleaner(wskprops) {
         (wp, assetHelper) =>
             val name = "helloSwift"
             assetHelper.withCleaner(wsk.action, name) {
@@ -68,30 +70,6 @@ class SwiftTests
             }
     }
 
-    /**
-     * Test the Swift 3 example
-     *
-     * It is ignored because Swift3 is experimental. The test is failed sometimes and breaks the CI pipeline. This was agreed.
-     */
-    ignore should "invoke a swift:3 action" in withAssetCleaner(wskprops) {
-        (wp, assetHelper) =>
-            val name = "helloSwift3"
-            assetHelper.withCleaner(wsk.action, name) {
-                (action, _) =>
-                    action.create(
-                        name,
-                        Some(TestUtils.getTestActionFilename("httpGet.swift")),
-                        kind = Some("swift:3"))
-            }
-
-            withActivation(wsk.activation, wsk.action.invoke(name), totalWait = activationPollDuration) {
-                activation =>
-                    val result = activation.response.result.get
-                    result.toString should include(""""url":"https://httpbin.org/get"""")
-                    result.toString should not include ("Error")
-            }
-    }
-
     behavior of "Swift 3 Whisk SDK tests"
 
     it should "allow Swift actions to invoke other actions" in withAssetCleaner(wskprops) {
@@ -100,7 +78,7 @@ class SwiftTests
             val file = TestUtils.getTestActionFilename("invoke.swift")
             val actionName = "invokeAction"
             assetHelper.withCleaner(wsk.action, actionName) {
-                (action, _) => action.create(name = actionName, artifact = Some(file), kind = Some("swift:3"))
+                (action, _) => action.create(name = actionName, artifact = Some(file), kind = Some(runtimeContainer))
             }
 
             // invoke the action
@@ -124,7 +102,7 @@ class SwiftTests
             val file = TestUtils.getTestActionFilename("invokeNonBlocking.swift")
             val actionName = "invokeNonBlockingAction"
             assetHelper.withCleaner(wsk.action, actionName) {
-                (action, _) => action.create(name = actionName, artifact = Some(file), kind = Some("swift:3"))
+                (action, _) => action.create(name = actionName, artifact = Some(file), kind = Some(runtimeContainer))
             }
 
             // invoke the action
@@ -151,7 +129,7 @@ class SwiftTests
             val file = TestUtils.getTestActionFilename("trigger.swift")
             val actionName = "ActionThatTriggers"
             assetHelper.withCleaner(wsk.action, actionName) {
-                (action, _) => action.create(name = actionName, artifact = Some(file), kind = Some("swift:3"))
+                (action, _) => action.create(name = actionName, artifact = Some(file), kind = Some(runtimeContainer))
             }
 
             // invoke the action
diff --git a/tools/build/redo b/tools/build/redo
index ac372c9..321b60b 100755
--- a/tools/build/redo
+++ b/tools/build/redo
@@ -291,6 +291,11 @@ Components = [
                   yaml = False,
                   gradle = 'core:swift3Action'),
 
+    makeComponent('action-swift-v3.1.1',
+                  'build swift v3.1.1 action container',
+                  yaml = False,
+                  gradle = 'core:swift3.1.1Action'),
+
     makeComponent('java8action',
                   'build java action container',
                   yaml = False,

-- 
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>'].