You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ra...@apache.org on 2018/07/23 15:12:38 UTC

[incubator-openwhisk-runtime-ruby] branch master updated (776c15e -> 0189b81)

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

rabbah pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-runtime-ruby.git.


    from 776c15e  Placeholder.
     new 45c55fa  Initial commit
     new f46575c  fixed a few errors and typos
     new c451ec0  remove an unnecessary file
     new ab31ca3  remove debugging code
     new 456d5d6  add LF to README.md to make scanCode pass
     new 3f666fc  Removed unnecessary files and added dirs/files for travis integration
     new d5c7545  Add travis CI status badge
     new 3136d81  Make tools/travis/+.sh executable
     new d8d3ffa  Add license headers to make CI passed
     new 8dc9b29  Make tools/travis/+.sh executable
     new 956d2a2  Add necessary file for TravisCI
     new a81f0d4  Fix an error in publish.sh
     new cb56b63  Fix a bug in scalafmt validation
     new 6c003ce  Update tests to pick up upstream changes.
     new 527a903   Add more boundary checking to pass new test cases
     new 75c934f  Replace wrong code snippet existed in the test case
     new dc1f958  Add another boundary for sentinel handling to make testInitCannotBeCalledMoreThanOnce work
     new 94caefc  Fixed a few errors based on the feedback from @rabbah
     new 0189b81  Remove deprecated documentation from README.md

The 19 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |  72 ++++
 .scalafmt.conf                                     |   9 +
 .travis.yml                                        |  41 ++
 LICENSE                                            | 191 ++++++++++
 README.md                                          |  99 ++++-
 build.gradle                                       |  13 +
 core/ruby2.5Action/Dockerfile                      |  24 ++
 core/ruby2.5Action/Gemfile                         |   4 +
 core/ruby2.5Action/build.gradle                    |   2 +
 core/ruby2.5Action/config.ru                       |  25 ++
 core/ruby2.5Action/rackapp/filepath.rb             |  16 +
 core/ruby2.5Action/rackapp/init.rb                 |  94 +++++
 core/ruby2.5Action/rackapp/middleware/base.rb      |   5 +
 .../rackapp/middleware/post_method_validation.rb   |  11 +
 .../rackapp/middleware/sentinel_handler.rb         |  13 +
 core/ruby2.5Action/rackapp/response/error.rb       |   5 +
 core/ruby2.5Action/rackapp/response/success.rb     |   5 +
 core/ruby2.5Action/rackapp/run.rb                  |  48 +++
 core/ruby2.5Action/rackapp/runner.rb               |   9 +
 gradle/README.md                                   |  64 ++++
 gradle/docker.gradle                               |  99 +++++
 gradle/wrapper/gradle-wrapper.jar                  | Bin 0 -> 54708 bytes
 gradle/wrapper/gradle-wrapper.properties           |   8 +
 gradlew                                            | 172 +++++++++
 gradlew.bat                                        |  84 +++++
 settings.gradle                                    |  19 +
 tests/.pydevproject                                |   5 +
 tests/build.gradle                                 |  44 +++
 tests/src/test/resources/application.conf          |   8 +
 .../Ruby25ActionContainerTests.scala               | 411 +++++++++++++++++++++
 tools/travis/build.sh                              |  43 +++
 tools/travis/publish.sh                            |  43 +++
 tools/travis/setup.sh                              |  34 ++
 tools/travis/test.sh                               |  30 ++
 34 files changed, 1749 insertions(+), 1 deletion(-)
 create mode 100644 .gitignore
 create mode 100644 .scalafmt.conf
 create mode 100644 .travis.yml
 create mode 100644 LICENSE
 create mode 100644 build.gradle
 create mode 100644 core/ruby2.5Action/Dockerfile
 create mode 100644 core/ruby2.5Action/Gemfile
 create mode 100644 core/ruby2.5Action/build.gradle
 create mode 100644 core/ruby2.5Action/config.ru
 create mode 100644 core/ruby2.5Action/rackapp/filepath.rb
 create mode 100644 core/ruby2.5Action/rackapp/init.rb
 create mode 100644 core/ruby2.5Action/rackapp/middleware/base.rb
 create mode 100644 core/ruby2.5Action/rackapp/middleware/post_method_validation.rb
 create mode 100644 core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
 create mode 100644 core/ruby2.5Action/rackapp/response/error.rb
 create mode 100644 core/ruby2.5Action/rackapp/response/success.rb
 create mode 100644 core/ruby2.5Action/rackapp/run.rb
 create mode 100644 core/ruby2.5Action/rackapp/runner.rb
 create mode 100644 gradle/README.md
 create mode 100644 gradle/docker.gradle
 create mode 100644 gradle/wrapper/gradle-wrapper.jar
 create mode 100644 gradle/wrapper/gradle-wrapper.properties
 create mode 100755 gradlew
 create mode 100755 gradlew.bat
 create mode 100644 settings.gradle
 create mode 100644 tests/.pydevproject
 create mode 100644 tests/build.gradle
 create mode 100644 tests/src/test/resources/application.conf
 create mode 100644 tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
 create mode 100755 tools/travis/build.sh
 create mode 100644 tools/travis/publish.sh
 create mode 100755 tools/travis/setup.sh
 create mode 100755 tools/travis/test.sh


[incubator-openwhisk-runtime-ruby] 09/19: Add license headers to make CI passed

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d8d3ffa179b0a08647c312c1ba9814fd2e4ad103
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 21:15:41 2018 +0900

    Add license headers to make CI passed
---
 README.md                                | 19 +++++++++++++++++++
 gradle/wrapper/gradle-wrapper.properties |  3 +++
 tools/travis/build.sh                    |  0
 tools/travis/publish.sh                  |  0
 tools/travis/setup.sh                    |  0
 tools/travis/test.sh                     |  0
 6 files changed, 22 insertions(+)

diff --git a/README.md b/README.md
index e71bcae..9235c3c 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,22 @@
+<!--
+#
+# 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.
+#
+-->
+
 # Apache OpenWhisk runtimes for Ruby
 [![Build Status](https://travis-ci.org/remore/openwhisk-runtime-ruby.svg?branch=master)](https://travis-ci.org/remore/openwhisk-runtime-ruby)
 
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f16d266..d7cc33f 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,3 +1,6 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
diff --git a/tools/travis/build.sh b/tools/travis/build.sh
old mode 100755
new mode 100644
diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
old mode 100755
new mode 100644
diff --git a/tools/travis/setup.sh b/tools/travis/setup.sh
old mode 100755
new mode 100644
diff --git a/tools/travis/test.sh b/tools/travis/test.sh
old mode 100755
new mode 100644


[incubator-openwhisk-runtime-ruby] 05/19: add LF to README.md to make scanCode pass

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 456d5d6753f334f01a99da6dbfc4a718f3321fea
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Wed Jun 6 10:18:31 2018 +0900

    add LF to README.md to make scanCode pass
---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 5e25b9e..8787af5 100644
--- a/README.md
+++ b/README.md
@@ -87,3 +87,4 @@ Using IntelliJ:
 -Dhttp.proxyHost=localhost
 -Dhttp.proxyPort=3128
 ```
+


[incubator-openwhisk-runtime-ruby] 04/19: remove debugging code

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ab31ca3f890ccdfc2170aff35b7ceb06b047f2cd
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Tue Jun 5 22:01:16 2018 +0900

    remove debugging code
---
 tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
index c581273..4075cf6 100644
--- a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -47,7 +47,6 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
           |def main(args)
           |  puts 'hello stdout'
           |  warn 'hello stderr'
-          |  #require 'net/http'; require 'uri'; res = Net::HTTP.post_form(URI.parse('http://remore-mockbin.herokuapp.com/bin/38e74975-104b-4733-9d90-834aaf14f909'), {'q'=>args, 'max'=>args.class.to_s})
           |  args
           |end
           """.stripMargin)


[incubator-openwhisk-runtime-ruby] 13/19: Fix a bug in scalafmt validation

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit cb56b6311ce31fc159173a8696664260fa3ab1bb
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Sat Jul 14 01:27:11 2018 +0900

    Fix a bug in scalafmt validation
---
 tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
index 4075cf6..4605305 100644
--- a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -282,7 +282,7 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
     }
   }
 
- val exampleOutputDotRuby: String = """
+  val exampleOutputDotRuby: String = """
         | def output(data)
         |   {'result' => data}
         | end


[incubator-openwhisk-runtime-ruby] 11/19: Add necessary file for TravisCI

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 956d2a241fee46c6c089ea1a663e060316dfd798
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 21:30:09 2018 +0900

    Add necessary file for TravisCI
---
 .scalafmt.conf | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/.scalafmt.conf b/.scalafmt.conf
new file mode 100644
index 0000000..7084efe
--- /dev/null
+++ b/.scalafmt.conf
@@ -0,0 +1,9 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+
+style = intellij
+danglingParentheses = false
+maxColumn = 120
+docstrings = JavaDoc
+rewrite.rules = [SortImports]
+project.git = true


[incubator-openwhisk-runtime-ruby] 15/19: Add more boundary checking to pass new test cases

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 527a903d9a85818d6c2fa29413da053b85ae2810
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Sun Jul 15 00:38:34 2018 +0900

     Add more boundary checking to pass new test cases
---
 core/ruby2.5Action/rackapp/init.rb                 | 15 ++++++++++--
 .../Ruby25ActionContainerTests.scala               | 27 ----------------------
 2 files changed, 13 insertions(+), 29 deletions(-)

diff --git a/core/ruby2.5Action/rackapp/init.rb b/core/ruby2.5Action/rackapp/init.rb
index d5316e8..55f7151 100644
--- a/core/ruby2.5Action/rackapp/init.rb
+++ b/core/ruby2.5Action/rackapp/init.rb
@@ -5,10 +5,21 @@ require "#{__dir__}/filepath.rb"
 class InitApp
   include Filepath
 
-  def call(env) 
+  def call(env)
+    # Make sure that this action is not initialised more than once
+    if File.exist? CONFIG then
+      return ErrorResponse.new 'Cannot initialize the action more than once.', 403
+    end
+
     # Expect JSON data input
     body = Rack::Request.new(env).body.read
     data = JSON.parse(body)['value'] || {}
+
+    # Is the input data empty?
+    if data == {} then
+      return ErrorResponse.new 'Missing main/no code to execute.', 500
+    end
+
     name = data['name'] || ''           # action name
     main = data['main'] || ''           # function to call
     code = data['code'] || ''           # source code to run
@@ -79,4 +90,4 @@ class InitApp
     rescue
       false
     end
-end
\ No newline at end of file
+end
diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
index cd23809..6622cc0 100644
--- a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -145,19 +145,6 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
     })
   }
 
-  it should "fail to initialize with no code" in {
-    val (out, err) = withRuby25Container { c =>
-      val code = ""
-
-      val (initCode, error) = c.init(initPayload(code))
-
-      initCode should not be (200)
-      error shouldBe a[Some[_]]
-      error.get shouldBe a[JsObject]
-      error.get.fields("error").toString should include("method checking failed")
-    }
-  }
-
   it should "return some error on action error" in {
     val (out, err) = withRuby25Container { c =>
       val code = """
@@ -407,20 +394,6 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
     })
   }
 
-  it should "support actions using non-default entry point" in {
-    val (out, err) = withRuby25Container { c =>
-      val code = """
-            | def niam(args)
-            |   { :result => "it works" }
-            | end
-            """.stripMargin
-
-      c.init(initPayload(code, main = "niam"))._1 should be(200)
-      val (runCode, runRes) = c.run(runPayload(JsObject()))
-      runRes.get.fields.get("result") shouldBe Some(JsString("it works"))
-    }
-  }
-
   it should "support zipped actions using non-default entry point" in {
     val srcs = Seq(Seq("main.rb") -> """
                 | def niam(args)


[incubator-openwhisk-runtime-ruby] 08/19: Make tools/travis/+.sh executable

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3136d813eb55acd6766af09e8925d8daa21a28cf
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 21:09:26 2018 +0900

    Make tools/travis/+.sh executable
---
 tools/travis/build.sh   | 0
 tools/travis/publish.sh | 0
 tools/travis/setup.sh   | 0
 tools/travis/test.sh    | 0
 4 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/tools/travis/build.sh b/tools/travis/build.sh
old mode 100644
new mode 100755
diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
old mode 100644
new mode 100755
diff --git a/tools/travis/setup.sh b/tools/travis/setup.sh
old mode 100644
new mode 100755
diff --git a/tools/travis/test.sh b/tools/travis/test.sh
old mode 100644
new mode 100755


[incubator-openwhisk-runtime-ruby] 07/19: Add travis CI status badge

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d5c75450c73b14560de6109cdba5123fcbc97eda
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 21:04:15 2018 +0900

    Add travis CI status badge
---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 8787af5..e71bcae 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
 # Apache OpenWhisk runtimes for Ruby
+[![Build Status](https://travis-ci.org/remore/openwhisk-runtime-ruby.svg?branch=master)](https://travis-ci.org/remore/openwhisk-runtime-ruby)
 
 ### Give it a try today
 To use as a docker action


[incubator-openwhisk-runtime-ruby] 19/19: Remove deprecated documentation from README.md

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0189b8148452dfae52e3b06c663d50bfcc48c174
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Mon Jul 23 22:06:59 2018 +0900

    Remove deprecated documentation from README.md
---
 README.md | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/README.md b/README.md
index aef2d9e..7c0bc4c 100644
--- a/README.md
+++ b/README.md
@@ -84,13 +84,6 @@ Install dependencies from the root directory on $OPENWHISK_HOME repository
 ./gradlew install
 ```
 
-Using gradle for the ActionContainer tests you need to use a proxy if running on Mac, if Linux then don't use proxy options
-You can pass the flags `-Dhttp.proxyHost=localhost -Dhttp.proxyPort=3128` directly in gradle command.
-Or save in your `$HOME/.gradle/gradle.properties`
-```
-systemProp.http.proxyHost=localhost
-systemProp.http.proxyPort=3128
-```
 Using gradle to run all tests
 ```
 ./gradlew :tests:test
@@ -102,9 +95,4 @@ Using gradle to run some tests
 Using IntelliJ:
 - Import project as gradle project.
 - Make sure working directory is root of the project/repo
-- Add the following Java VM properties in ScalaTests Run Configuration, easiest is to change the Defaults for all ScalaTests to use this VM properties
-```
--Dhttp.proxyHost=localhost
--Dhttp.proxyPort=3128
-```
 


[incubator-openwhisk-runtime-ruby] 03/19: remove an unnecessary file

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c451ec0bf5d8bc4f361a4bd9b8bb525c95a7b1a4
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Tue Jun 5 21:28:37 2018 +0900

    remove an unnecessary file
---
 sshconfig | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/sshconfig b/sshconfig
deleted file mode 100644
index 95d1af6..0000000
--- a/sshconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-Host default
-  HostName 127.0.0.1
-  User vagrant
-  Port 2222
-  UserKnownHostsFile /dev/null
-  StrictHostKeyChecking no
-  PasswordAuthentication no
-  IdentityFile /Users/ksawada/src/github/openwhisk/tools/vagrant/.vagrant/machines/default/virtualbox/private_key
-  IdentitiesOnly yes
-  LogLevel FATAL
-  ForwardAgent yes
-


[incubator-openwhisk-runtime-ruby] 06/19: Removed unnecessary files and added dirs/files for travis integration

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3f666fc8a871c4dd709f0b2fee8b26025eb3099f
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 21:00:04 2018 +0900

    Removed unnecessary files and added dirs/files for travis integration
---
 .travis.yml                               | 41 ++++++++++++++++++++++++++
 ansible/environments/local/group_vars/all | 46 -----------------------------
 ansible/environments/local/hosts          | 29 ------------------
 tools/travis/build.sh                     | 43 +++++++++++++++++++++++++++
 tools/travis/publish.sh                   | 49 +++++++++++++++++++++++++++++++
 tools/travis/setup.sh                     | 34 +++++++++++++++++++++
 tools/travis/test.sh                      | 30 +++++++++++++++++++
 7 files changed, 197 insertions(+), 75 deletions(-)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..745c73b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+
+sudo: required
+group: deprecated-2017Q3
+language: scala
+scala:
+- 2.11.11
+services:
+  - docker
+before_install:
+  - "./tools/travis/setup.sh"
+install: true
+script:
+  - "./tools/travis/build.sh && ./tools/travis/test.sh"
+deploy:
+  - provider: script
+    script: "./tools/travis/publish.sh openwhisk ${TRAVIS_TAG%@*} ${TRAVIS_TAG##*@}"
+    on:
+      tags: true
+      all_branches: true
+      repo: apache/incubator-openwhisk-runtime-ruby
+  - provider: script
+    script: "./tools/travis/publish.sh openwhisk 2 latest && ./tools/travis/publish.sh openwhisk 3 latest"
+    on:
+      branch: master
+      repo: apache/incubator-openwhisk-runtime-ruby
+env:
+  global:
+  - secure: Ac7MlWUpsLwmbcjCigDf+vftiXAEJbf78FVm2QCd4IeFqlRiNbQm3bWRXOOW3Zqh4R4o/wSFpFq0qKPrI9WJjOcxD0GxFboq2iGWTegddfDbENV/IBmjurl6NzYY6dUB7GUSmHYy6tdKnxMhjHzZCn2m4OVWltcMtnOV0G+uYvbnre7vXfb67duzJF+mYpJJ7rC0wGh+N50bYvm0BTtPcQMYJibq6sDTY8Lr1b74QGdM/sODre69CbuiwAA7Ed0hajEcMkv8YnwY0De/PL7hthUyCWSD+i1AhtD+3odA64yX/pAbBzfCcqPoI0Nt5ZmAAUKLJ9pAHCc74dlmYzj9wj1z5TS0nLOE2l++vNvgsA3/c+lqrBv6hc9FmSKx4yfNdFCakVLEfdRJw/45ibIRN5dCW5tDdIx8aciBV8c0CyYgSLRvtVuvw5IX7fbwhHOZ8ftTRzCHS0Nd9zs4x3za+1aucWFQEyrk [...]
+  - secure: fte97QoQReAM0obk/tjxYvF/zhRbcyIFxa1jnFuv1m1YKA/pEWue5uMIDZZa1pynN9rFFgOvR2W34Gm2aHl0wJs18Oqi2Es1cSfDDmuYguEIYZmlfbrjXY2gvitH5+6JA6fc4aMmrgOav+WVbzdzBqy511CWEDsejWflAnFpKJqTnYdLqe8L8FAJfteY/cj5Bvz7G5o8WbH+ag2CopjkEKkx4KXsJ7DadKI+BbI9hkMUvPVnTULaf7Q5z3oG92g1XwjKrfN6Z2y8tQukWg+n5pfVY0yLpWvd/Q/9HyilB0s06EzORzE00DTLnvYNGaVsx99m6H11e0Tn5Sx5S6rJOmJa5T2vTPGmsojpgHm1Lz12AYVxRmWvFbTLg8KDNN9H6uTc8DKPGb/mLkkD5ruWXJWjvpd+m+eRcpJOZ9cvPXWFYvCF0VAPCbK0DakInnmCvZyQ6ZLFgGrtkNt51kkTZGR68d0UW9rw [...]
+notifications:
+  slack:
+    secure: ipYx0BX7TwWmG+qeyAllxBxrPn21dJubfEbALn8yTOZfykTWpVtohWrqieAnc6kFQRqz1TAs1wzyjvTcutaIMi9C7FcJrYRIMUMpyID3ca5FeZopr/LBW53XHj/SgZWwFRAnWsjYnSydfZJnUBInI6por8jdVqVgsCMTDsvcXFEoHdVj9M93aB7y8pgqZhfYkQOPojktDu7nMxjsjKJN7dT+g/1kVWtS8DQQCXHTPP44YquxOCgAFn+CZjes9Jm+vz5lk5Azksi48yiHwFiLYZo5gcnwr2n2IspjBs6db10rkCe693vIpoW4T3KujMIKwVXrgUl4pDME1nN/loEBHm0DjKoeOD13DHqITMTPX4sR94TCGf0lMyaag/JOETdDgC9hAbh4aSx1cj4hGXiuGrNMbYblMBsjvujqFp2nraw/DE93pHGRY9lbBZIjEVhj/jBmOv1I3yRdXHj4VybZc4JGnfQVGz/R [...]
+    on_pull_requests: false
+    on_success: change
+    on_failure: always
+  webhooks:
+    urls:
+      # travis2slack webhook to enable DMs on openwhisk-team.slack.com to PR authors with TravisCI results
+      secure: "jhiMGpQ6kJFWjjsO68RmgD2Lga7jgNE+EKwND0dMOvzf5llMLFDKcY5J3tgtrqYaslQdXeuYeru/9qJrTTjFEu+vz3iCwoJ/eme+D0TtTIFGlPr7oa9tZlWrkPM/0zFLq7KjJauIIX2+6qrGVrNJJ6ENfr4U8Ir8q51oLIk44bsCeB8EmkahPOlNG6kcNqgpxHWKYUdUIg3B0GxqCKida/76dXDTRHCV2dZuT2bXz2oSJYog/lybomsjQIUZj0+HqxecgWTzag3Y6rTpK+m+vywazHP91hE+oU4e7YrxCH6v9+ukoWaljFqO5ZEKXcpx6tzx8Q0FvoTP8vGOO9b/t1loVcA8OxSJDrtOAztfoz/u0HJN6vnVt+maqnrYAD1F4pxA63JA6/+a7firmtADP7A/WQMZg6RgEkGUr+amFn303dTvgjDDkZ4oH8MAr0EPsneGUA2MZgB3i1MEcnCrYzT7KpYmD [...]
diff --git a/ansible/environments/local/group_vars/all b/ansible/environments/local/group_vars/all
deleted file mode 100644
index 1a8251d..0000000
--- a/ansible/environments/local/group_vars/all
+++ /dev/null
@@ -1,46 +0,0 @@
-whisk_version_name: local
-openwhisk_tmp_dir: "{{ lookup('env', 'OPENWHISK_TMP_DIR')|default('/tmp', true) }}"
-config_root_dir: "{{ openwhisk_tmp_dir }}/wskconf"
-whisk_logs_dir: "{{ openwhisk_tmp_dir }}/wsklogs"
-docker_registry: ""
-docker_dns: ""
-runtimes_bypass_pull_for_local_images: true
-invoker_use_runc: "{{ ansible_distribution != 'MacOSX' }}"
-
-db_prefix: whisk_local_
-
-# Auto lookup to find the db credentials
-db_provider: "{{ lookup('ini', 'db_provider section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
-db_username: "{{ lookup('ini', 'db_username section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
-db_password: "{{ lookup('ini', 'db_password section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
-db_protocol: "{{ lookup('ini', 'db_protocol section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
-db_host: "{{ lookup('ini', 'db_host section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
-db_port: "{{ lookup('ini', 'db_port section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
-
-# API GW connection configuration
-apigw_auth_user: ""
-apigw_auth_pwd: ""
-apigw_host_v2: "http://{{ groups['apigateway']|first }}:{{apigateway.port.api}}/v2"
-
-invoker_allow_multiple_instances: true
-
-env_hosts_dir: "{{ playbook_dir }}/environments/local"
-
-runtimes_manifest:
-  defaultImagePrefix: "openwhisk"
-  defaultImageTag: "latest"
-  runtimes:
-    nodejs:
-    - kind: "nodejs:6"
-      default: true
-      image:
-        name: "nodejs6action"
-      deprecated: false
-    ruby:
-    - kind: "ruby:2.5"
-      default: true
-      image:
-        name: "action-ruby-v2.5"
-      deprecated: false
-  blackboxes:
-    - name: "dockerskeleton"
diff --git a/ansible/environments/local/hosts b/ansible/environments/local/hosts
deleted file mode 100644
index 4715e55..0000000
--- a/ansible/environments/local/hosts
+++ /dev/null
@@ -1,29 +0,0 @@
-; the first parameter in a host is the inventory_hostname
-
-; used for local actions only
-ansible ansible_connection=local
-
-[edge]
-172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
-
-[controllers]
-controller0         ansible_host=172.17.0.1 ansible_connection=local
-
-[kafkas]
-kafka0              ansible_host=172.17.0.1 ansible_connection=local
-
-[zookeepers:children]
-kafkas
-
-[invokers]
-invoker0            ansible_host=172.17.0.1 ansible_connection=local
-
-; db group is only used if db_provider is CouchDB
-[db]
-172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
-
-[redis]
-172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
-
-[apigateway]
-172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
diff --git a/tools/travis/build.sh b/tools/travis/build.sh
new file mode 100644
index 0000000..e3aa931
--- /dev/null
+++ b/tools/travis/build.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -ex
+
+# Build script for Travis-CI.
+
+SCRIPTDIR=$(cd $(dirname "$0") && pwd)
+ROOTDIR="$SCRIPTDIR/../.."
+WHISKDIR="$ROOTDIR/../openwhisk"
+UTILDIR="$ROOTDIR/../incubator-openwhisk-utilities"
+
+export OPENWHISK_HOME=$WHISKDIR
+
+# run scancode using the ASF Release configuration
+cd $UTILDIR
+scancode/scanCode.py --config scancode/ASF-Release.cfg $ROOTDIR
+
+# Build OpenWhisk deps before we run tests
+cd $WHISKDIR
+TERM=dumb ./gradlew install
+# Mock file (works around bug upstream)
+echo "openwhisk.home=$WHISKDIR" > whisk.properties
+echo "vcap.services.file=" >> whisk.properties
+
+# Build runtime
+cd $ROOTDIR
+TERM=dumb ./gradlew distDocker
diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
new file mode 100644
index 0000000..4ff9ec3
--- /dev/null
+++ b/tools/travis/publish.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -eux
+
+# Build script for Travis-CI.
+
+SCRIPTDIR=$(cd $(dirname "$0") && pwd)
+ROOTDIR="$SCRIPTDIR/../.."
+WHISKDIR="$ROOTDIR/../openwhisk"
+
+export OPENWHISK_HOME=$WHISKDIR
+
+IMAGE_PREFIX=$1
+RUNTIME_VERSION=$2
+IMAGE_TAG=$3
+
+if [ ${RUNTIME_VERSION} == "2" ]; then
+  RUNTIME="python2Action"
+elif [ ${RUNTIME_VERSION} == "3" ]; then
+  RUNTIME="pythonAction"
+fi
+
+if [[ ! -z ${DOCKER_USER} ]] && [[ ! -z ${DOCKER_PASSWORD} ]]; then
+docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
+fi
+
+if [[ ! -z ${RUNTIME} ]]; then
+TERM=dumb ./gradlew \
+:core:${RUNTIME}:distDocker \
+-PdockerRegistry=docker.io \
+-PdockerImagePrefix=${IMAGE_PREFIX} \
+-PdockerImageTag=${IMAGE_TAG}
+fi
diff --git a/tools/travis/setup.sh b/tools/travis/setup.sh
new file mode 100644
index 0000000..3424cdb
--- /dev/null
+++ b/tools/travis/setup.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -e
+
+# Build script for Travis-CI.
+
+SCRIPTDIR=$(cd $(dirname "$0") && pwd)
+ROOTDIR="$SCRIPTDIR/../.."
+HOMEDIR="$SCRIPTDIR/../../../"
+
+# clone OpenWhisk utilities repo. in order to run scanCode
+cd $HOMEDIR
+git clone https://github.com/apache/incubator-openwhisk-utilities.git
+
+# clone main openwhisk repo. for testing purposes
+git clone --depth=1 https://github.com/apache/incubator-openwhisk.git openwhisk
+cd openwhisk
+./tools/travis/setup.sh
diff --git a/tools/travis/test.sh b/tools/travis/test.sh
new file mode 100644
index 0000000..a5b249d
--- /dev/null
+++ b/tools/travis/test.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -ex
+
+# Build script for Travis-CI.
+
+SCRIPTDIR=$(cd $(dirname "$0") && pwd)
+ROOTDIR="$SCRIPTDIR/../.."
+WHISKDIR="$ROOTDIR/../openwhisk"
+
+export OPENWHISK_HOME=$WHISKDIR
+cd ${ROOTDIR}
+TERM=dumb ./gradlew :tests:checkScalafmtAll
+TERM=dumb ./gradlew :tests:test


[incubator-openwhisk-runtime-ruby] 18/19: Fixed a few errors based on the feedback from @rabbah

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 94caefc0d903cdbe144f5b942e8556db0cb6500c
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Mon Jul 23 11:18:03 2018 +0900

    Fixed a few errors based on the feedback from @rabbah
---
 README.md                                                              | 2 +-
 tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala | 2 --
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 9235c3c..aef2d9e 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@
 -->
 
 # Apache OpenWhisk runtimes for Ruby
-[![Build Status](https://travis-ci.org/remore/openwhisk-runtime-ruby.svg?branch=master)](https://travis-ci.org/remore/openwhisk-runtime-ruby)
+[![Build Status](https://travis-ci.org/apache/incubator-openwhisk-runtime-ruby.svg?branch=master)](https://travis-ci.org/apache/incubator-openwhisk-runtime-ruby)
 
 ### Give it a try today
 To use as a docker action
diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
index e3b8f89..1090c14 100644
--- a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -115,8 +115,6 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
   override val testLargeInput = {
     TestConfig("""
         |def main(args)
-        |  puts 'hello stdout'
-        |  warn 'hello stderr'
         |  args
         |end
       """.stripMargin)


[incubator-openwhisk-runtime-ruby] 14/19: Update tests to pick up upstream changes.

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6c003ce9418bdfe7c0ec5641f0c729f8c6509225
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Sat Jul 14 23:38:44 2018 +0900

    Update tests to pick up upstream changes.
---
 .../Ruby25ActionContainerTests.scala               | 107 ++++++++++++++-------
 1 file changed, 70 insertions(+), 37 deletions(-)

diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
index 4605305..cd23809 100644
--- a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -40,55 +40,88 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
 
   behavior of ruby25ContainerImageName
 
-  testEcho(Seq {
-    (
-      "RUBY",
+  override val testNoSourceOrExec = TestConfig("")
+
+  override val testEcho = {
+    TestConfig("""
+                 |def main(args)
+                 |  puts 'hello stdout'
+                 |  warn 'hello stderr'
+                 |  args
+                 |end
+               """.stripMargin)
+  }
+
+  override val testNotReturningJson = {
+    TestConfig(
+      """
+       |def main(args)
+       |  "not a json object"
+       |end
+     """.stripMargin,
+      enforceEmptyOutputStream = enforceEmptyOutputStream,
+      enforceEmptyErrorStream = false)
+  }
+
+  override val testInitCannotBeCalledMoreThanOnce = {
+    TestConfig(
       """
-          |def main(args)
-          |  puts 'hello stdout'
-          |  warn 'hello stderr'
-          |  args
-          |end
-          """.stripMargin)
-  })
-
-  testNotReturningJson("""
         |def main(args)
-        |  "not a json object"
+        |  args
         |end
-        """.stripMargin)
+      """.stripMargin,
+      enforceEmptyOutputStream = enforceEmptyOutputStream)
+  }
 
-  testUnicode(Seq {
-    (
-      "RUBY",
+  override val testEntryPointOtherThanMain = {
+    TestConfig(
       """
+        |def niam(args)
+        |  args
+        |end
+      """.stripMargin,
+      main = "niam",
+      enforceEmptyOutputStream = enforceEmptyOutputStream)
+  }
+
+  override val testUnicode = {
+    TestConfig("""
          |def main(args)
          |  str = args['delimiter'] + " ☃ " + args['delimiter']
          |  print str + "\n"
          |  {"winter" => str}
          |end
          """.stripMargin.trim)
-  })
+  }
 
-  testEnv(
-    Seq {
-      (
-        "RUBY",
-        """
-         |def main(args)
-         |  {
-         |       "env" => ENV,
-         |       "api_host" => ENV['__OW_API_HOST'],
-         |       "api_key" => ENV['__OW_API_KEY'],
-         |       "namespace" => ENV['__OW_NAMESPACE'],
-         |       "action_name" => ENV['__OW_ACTION_NAME'],
-         |       "activation_id" => ENV['__OW_ACTIVATION_ID'],
-         |       "deadline" => ENV['__OW_DEADLINE']
-         |  }
-         |end
-         """.stripMargin.trim)
-    },
-    enforceEmptyOutputStream)
+  override val testEnv = {
+    TestConfig(
+      """
+        |def main(args)
+        |  {
+        |       "env" => ENV,
+        |       "api_host" => ENV['__OW_API_HOST'],
+        |       "api_key" => ENV['__OW_API_KEY'],
+        |       "namespace" => ENV['__OW_NAMESPACE'],
+        |       "action_name" => ENV['__OW_ACTION_NAME'],
+        |       "activation_id" => ENV['__OW_ACTIVATION_ID'],
+        |       "deadline" => ENV['__OW_DEADLINE']
+        |  }
+        |end
+      """.stripMargin.trim,
+      enforceEmptyOutputStream = enforceEmptyOutputStream)
+  }
+
+  override val testLargeInput = {
+    TestConfig("""
+        |<?php
+        |function main(array $args) : array {
+        |    echo 'hello stdout';
+        |    error_log('hello stderr');
+        |    return $args;
+        |}
+      """.stripMargin)
+  }
 
   it should "fail to initialize with bad code" in {
     val (out, err) = withRuby25Container { c =>


[incubator-openwhisk-runtime-ruby] 16/19: Replace wrong code snippet existed in the test case

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 75c934f2ff2a308ae121ea18ab707a619d46ee84
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Sun Jul 15 01:12:24 2018 +0900

    Replace wrong code snippet existed in the test case
---
 .../scala/actionContainers/Ruby25ActionContainerTests.scala   | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
index 6622cc0..e3b8f89 100644
--- a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -114,12 +114,11 @@ class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSys
 
   override val testLargeInput = {
     TestConfig("""
-        |<?php
-        |function main(array $args) : array {
-        |    echo 'hello stdout';
-        |    error_log('hello stderr');
-        |    return $args;
-        |}
+        |def main(args)
+        |  puts 'hello stdout'
+        |  warn 'hello stderr'
+        |  args
+        |end
       """.stripMargin)
   }
 


[incubator-openwhisk-runtime-ruby] 01/19: Initial commit

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 45c55fada863a43466e432b6d538c3b746dabee9
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Tue Jun 5 20:46:21 2018 +0900

    Initial commit
---
 .gitignore                                         |  72 ++++
 LICENSE                                            | 191 ++++++++++
 README.md                                          |   1 -
 ansible/environments/local/group_vars/all          |  46 +++
 ansible/environments/local/hosts                   |  29 ++
 build.gradle                                       |  13 +
 core/ruby2.5Action/Dockerfile                      |  24 ++
 core/ruby2.5Action/Gemfile                         |   4 +
 core/ruby2.5Action/build.gradle                    |   2 +
 core/ruby2.5Action/config.ru                       |  75 ++++
 core/ruby2.5Action/rackapp/filepath.rb             |  16 +
 core/ruby2.5Action/rackapp/init.rb                 |  88 +++++
 core/ruby2.5Action/rackapp/middleware/base.rb      |   5 +
 .../rackapp/middleware/post_method_validation.rb   |  11 +
 .../rackapp/middleware/sentinel_handler.rb         |  14 +
 core/ruby2.5Action/rackapp/response/error.rb       |   6 +
 core/ruby2.5Action/rackapp/response/success.rb     |   5 +
 core/ruby2.5Action/rackapp/run.rb                  |  53 +++
 core/ruby2.5Action/rackapp/runner.rb               |   9 +
 gradle/README.md                                   |  64 ++++
 gradle/docker.gradle                               |  99 +++++
 gradle/wrapper/gradle-wrapper.jar                  | Bin 0 -> 54708 bytes
 gradle/wrapper/gradle-wrapper.properties           |   5 +
 gradlew                                            | 172 +++++++++
 gradlew.bat                                        |  84 +++++
 settings.gradle                                    |  19 +
 sshconfig                                          |  12 +
 tests/.pydevproject                                |   5 +
 tests/build.gradle                                 |  44 +++
 tests/src/test/resources/application.conf          |   8 +
 .../Ruby25ActionContainerTests.scala               | 409 +++++++++++++++++++++
 31 files changed, 1584 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ed2c749
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,72 @@
+# Whisk
+nginx.conf
+whisk.properties
+default.props
+
+.ant-targets-build.xml
+/results/
+/logs/
+/config/custom-config.xml
+results
+*.retry
+
+# Environments
+/ansible/environments/*
+!/ansible/environments/distributed
+!/ansible/environments/docker-machine
+!/ansible/environments/local
+!/ansible/environments/mac
+
+# Eclipse
+bin/
+**/.project
+.settings/
+.classpath
+.cache-main
+.cache-tests
+
+# Linux
+*~
+
+# Mac
+.DS_Store
+
+# Gradle
+.gradle
+build/
+!/tools/build/
+
+# Python
+.ipynb_checkpoints/
+*.pyc
+
+# NodeJS
+node_modules
+
+# Vagrant
+.vagrant*
+
+# IntelliJ
+.idea
+*.class
+*.iml
+out/
+
+# Ansible
+ansible/environments/docker-machine/hosts
+ansible/db_local.ini*
+ansible/tmp/*
+ansible/roles/nginx/files/openwhisk-client*
+ansible/roles/nginx/files/*.csr
+ansible/roles/nginx/files/*cert.pem
+
+# .zip files must be explicited whitelisted
+*.zip
+!tests/dat/actions/blackbox.zip
+!tests/dat/actions/helloSwift.zip
+!tests/dat/actions/python.zip
+!tests/dat/actions/python2_virtualenv.zip
+!tests/dat/actions/python3_virtualenv.zip
+!tests/dat/actions/python_virtualenv_dir.zip
+!tests/dat/actions/python_virtualenv_name.zip
+!tests/dat/actions/zippedaction.zip
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cb4547d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,191 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2015 Kei Sawada
+
+   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
+
+       https://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.
diff --git a/README.md b/README.md
index cb2a042..e69de29 100644
--- a/README.md
+++ b/README.md
@@ -1 +0,0 @@
-# incubator-openwhisk-runtime-ruby
diff --git a/ansible/environments/local/group_vars/all b/ansible/environments/local/group_vars/all
new file mode 100644
index 0000000..1a8251d
--- /dev/null
+++ b/ansible/environments/local/group_vars/all
@@ -0,0 +1,46 @@
+whisk_version_name: local
+openwhisk_tmp_dir: "{{ lookup('env', 'OPENWHISK_TMP_DIR')|default('/tmp', true) }}"
+config_root_dir: "{{ openwhisk_tmp_dir }}/wskconf"
+whisk_logs_dir: "{{ openwhisk_tmp_dir }}/wsklogs"
+docker_registry: ""
+docker_dns: ""
+runtimes_bypass_pull_for_local_images: true
+invoker_use_runc: "{{ ansible_distribution != 'MacOSX' }}"
+
+db_prefix: whisk_local_
+
+# Auto lookup to find the db credentials
+db_provider: "{{ lookup('ini', 'db_provider section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
+db_username: "{{ lookup('ini', 'db_username section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
+db_password: "{{ lookup('ini', 'db_password section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
+db_protocol: "{{ lookup('ini', 'db_protocol section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
+db_host: "{{ lookup('ini', 'db_host section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
+db_port: "{{ lookup('ini', 'db_port section=db_creds file={{ playbook_dir }}/db_local.ini') }}"
+
+# API GW connection configuration
+apigw_auth_user: ""
+apigw_auth_pwd: ""
+apigw_host_v2: "http://{{ groups['apigateway']|first }}:{{apigateway.port.api}}/v2"
+
+invoker_allow_multiple_instances: true
+
+env_hosts_dir: "{{ playbook_dir }}/environments/local"
+
+runtimes_manifest:
+  defaultImagePrefix: "openwhisk"
+  defaultImageTag: "latest"
+  runtimes:
+    nodejs:
+    - kind: "nodejs:6"
+      default: true
+      image:
+        name: "nodejs6action"
+      deprecated: false
+    ruby:
+    - kind: "ruby:2.5"
+      default: true
+      image:
+        name: "action-ruby-v2.5"
+      deprecated: false
+  blackboxes:
+    - name: "dockerskeleton"
diff --git a/ansible/environments/local/hosts b/ansible/environments/local/hosts
new file mode 100644
index 0000000..4715e55
--- /dev/null
+++ b/ansible/environments/local/hosts
@@ -0,0 +1,29 @@
+; the first parameter in a host is the inventory_hostname
+
+; used for local actions only
+ansible ansible_connection=local
+
+[edge]
+172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
+
+[controllers]
+controller0         ansible_host=172.17.0.1 ansible_connection=local
+
+[kafkas]
+kafka0              ansible_host=172.17.0.1 ansible_connection=local
+
+[zookeepers:children]
+kafkas
+
+[invokers]
+invoker0            ansible_host=172.17.0.1 ansible_connection=local
+
+; db group is only used if db_provider is CouchDB
+[db]
+172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
+
+[redis]
+172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
+
+[apigateway]
+172.17.0.1          ansible_host=172.17.0.1 ansible_connection=local
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..300a1ce
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,13 @@
+buildscript {
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath "cz.alenkacz:gradle-scalafmt:${gradle.scalafmt.version}"
+    }
+}
+
+subprojects {
+    apply plugin: 'scalafmt'
+    scalafmt.configFilePath = gradle.scalafmt.config
+}
diff --git a/core/ruby2.5Action/Dockerfile b/core/ruby2.5Action/Dockerfile
new file mode 100644
index 0000000..4fd4ff0
--- /dev/null
+++ b/core/ruby2.5Action/Dockerfile
@@ -0,0 +1,24 @@
+FROM ruby:2.5
+
+# install dependencies
+RUN gem install \
+        bundler \
+        rubyzip \
+        rack \
+        puma \
+        rake          `#optional` \
+        mechanize     `#optional` \
+        activesupport `#optional` \
+        jwt           `#optional`
+
+# create src directory to store action files
+RUN mkdir -p /action/src
+ADD rackapp /action/rackapp/
+COPY config.ru /action
+
+# run webserver
+RUN cd /action
+EXPOSE 8080
+ENV BUNDLE_GEMFILE /action/src/Gemfile
+ENV RUBYOPT -EUTF-8
+CMD [ "puma", "/action/config.ru", "-b", "tcp://0.0.0.0:8080" ]
diff --git a/core/ruby2.5Action/Gemfile b/core/ruby2.5Action/Gemfile
new file mode 100644
index 0000000..7bd43ed
--- /dev/null
+++ b/core/ruby2.5Action/Gemfile
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+gem 'rack'
+gem 'rubyzip'
diff --git a/core/ruby2.5Action/build.gradle b/core/ruby2.5Action/build.gradle
new file mode 100644
index 0000000..5b36d4f
--- /dev/null
+++ b/core/ruby2.5Action/build.gradle
@@ -0,0 +1,2 @@
+ext.dockerImageName = 'action-ruby-v2.5'
+apply from: '../../gradle/docker.gradle'
diff --git a/core/ruby2.5Action/config.ru b/core/ruby2.5Action/config.ru
new file mode 100644
index 0000000..6b478fc
--- /dev/null
+++ b/core/ruby2.5Action/config.ru
@@ -0,0 +1,75 @@
+#!/usr/bin/ruby
+
+require 'rubygems'
+require 'json'
+require 'zip'
+require 'base64'
+
+#====== For Debugging Purpose Only
+module RackHelper
+  require 'uri'
+  require 'net/http'
+  class << self
+    def _p(name, value)
+      "#{name}: #{value}\n\n-------\n"
+    end
+
+    def log(value)
+      url = URI("http://SOME_URL_SUCH_AS_MOCKBIN/")
+      http = Net::HTTP.new(url.host, url.port)
+
+      req = Net::HTTP::Post.new(url)
+      req["accept"] = 'application/json'
+      req["content-type"] = 'application/x-www-form-urlencoded'
+      req.body = value
+      response = http.request(req)
+    end
+
+    def debug(env)
+      request = Rack::Request.new(env)
+      log _p(:ENV, ENV.to_a) +
+        _p(:request_params, request.params.to_a) + 
+        _p(:request_env, request.env) + 
+        _p(:request_POST, request.POST) + 
+        _p(:body, request.body.read)
+    end
+
+  end
+end
+#====== For Debugging Purpose Only
+
+require "#{__dir__}/rackapp/middleware/post_method_validation.rb"
+require "#{__dir__}/rackapp/middleware/sentinel_handler.rb"
+require "#{__dir__}/rackapp/init.rb"
+require "#{__dir__}/rackapp/run.rb"
+
+rackapp = Rack::Builder.app do
+  use HTTPPostMethodValidation
+  use SentinelHandler
+
+  #  {
+  #    "value":{
+  #      "name":   "myAction",
+  #      "binary": false,
+  #      "main":   "main",
+  #      "code":   "def main(params) {\\n  {payload: \\\"length = \\\" + params.to_s}\\n}\\n\"
+  #    }
+  #  }
+  map '/init' do
+    run InitApp.new
+  end
+
+  #  {
+  #    "activation_id":    "91f9fa332a424e35b9fa332a423e35fd",
+  #    "action_name":      "/guest/myAction",
+  #    "deadline":         "1526980345727",
+  #    "api_key":          "23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP",
+  #    "value":            {\"message\":\"hello\"},
+  #    "namespace":        "guest"
+  #  }
+  map "/run" do
+    run RunApp.new
+  end
+end
+
+run rackapp
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/filepath.rb b/core/ruby2.5Action/rackapp/filepath.rb
new file mode 100644
index 0000000..d660b15
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/filepath.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/ruby
+
+module Filepath
+  ROOT = '/action/'
+
+  CONFIG = ROOT + '.wsk.config'
+  TMP_ZIP = ROOT + 'action.zip'
+  PARAM = ROOT + '.wsk.param'
+  RESULT = ROOT + '.wsk.result'
+  OUT = ROOT + '.wsk.stdout'
+  ERR = ROOT + '.wsk.stderr'
+
+  PROGRAM_DIR = ROOT + 'src/'
+  RACKAPP_DIR = ROOT + 'rackapp/'
+  ENTRYPOINT = PROGRAM_DIR + 'main.rb'
+end
diff --git a/core/ruby2.5Action/rackapp/init.rb b/core/ruby2.5Action/rackapp/init.rb
new file mode 100644
index 0000000..3f85770
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/init.rb
@@ -0,0 +1,88 @@
+require "#{__dir__}/response/success.rb"
+require "#{__dir__}/response/error.rb"
+require "#{__dir__}/filepath.rb"
+
+class InitApp
+  def call(env) 
+    # RackHelper.debug env
+    # Expect JSON data input
+    body = Rack::Request.new(env).body.read
+    RackHelper.log body
+    data = JSON.parse(body)['value'] || {}
+    name = data['name'] || ''           # action name
+    main = data['main'] || ''           # function to call
+    code = data['code'] || ''           # source code to run
+    binary = data['binary'] || false    # code is binary?
+
+    # Are name/main/code variables instance of String?
+    if ![name, main, code].map{|e| e.is_a? String }.inject{|a,b| a && b } then
+      return ErrorResponse.new 'Invalid Parameters: failed to handle the request', 500
+    end
+
+    RackHelper.log env.to_json
+    env = {'BUNDLE_GEMFILE' => Filepath::PROGRAM_DIR + 'Gemfile'}
+    if binary then
+      File.write Filepath::TMP_ZIP, Base64.decode64(code)
+      if !unzip(Filepath::TMP_ZIP, Filepath::PROGRAM_DIR) then
+        return ErrorResponse.new 'Invalid Binary: failed to open zip file. Please make sure you have finishied $bundle package successfully.', 500
+      end
+      RackHelper.log `ls -alR #{Filepath::PROGRAM_DIR}`
+      # Try to resolve dependencies
+      if File.exist?(Filepath::PROGRAM_DIR + 'Gemfile') then
+        if !File.directory?(Filepath::PROGRAM_DIR + 'vendor/cache') then
+          return ErrorResponse.new 'Invalid Binary: vendor/cache folder is not found. Please make sure you have used valid zip binary.', 200
+        end
+        if !system(env, "bundle install --local 2> #{Filepath::ERR} 1> #{Filepath::OUT}") then
+          return ErrorResponse.new "Invalid Binary: failed to resolve dependencies / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}", 500
+        end
+      else
+        File.write env['BUNDLE_GEMFILE'], ''  # For better performance, better to remove Gemfile and remove "bundle exec" redundant call when binary=false. To be improved in future.
+      end
+      if !File.exist?(Filepath::ENTRYPOINT) then
+        return ErrorResponse.new 'Invalid Ruby Code: zipped actions must contain main.rb at the root.', 500
+      end
+    else
+      # Save the code for future use
+      File.write Filepath::ENTRYPOINT, code
+      File.write env['BUNDLE_GEMFILE'], ''  # For better performance, better to remove Gemfile and remove "bundle exec" redundant call when binary=false. To be improved in future.
+    end
+
+    # Check if the ENTRYPOINT code is valid or not
+    RackHelper.log "TRACK-Zero"
+    if !valid_code?(Filepath::ENTRYPOINT) then
+      RackHelper.log "TRACK-alpha / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}"
+      return ErrorResponse.new 'Invalid Ruby Code: failed to parse the input code', 500
+    end
+
+    RackHelper.log "TRACK-A"
+    # Check if the method exists as expected
+    if !system(env, "bundle exec ruby -r #{Filepath::ENTRYPOINT} -e \"method(:#{main}) ? true : raise(Exception.new('Error'))\" 2> #{Filepath::ERR} 1> #{Filepath::OUT}") then
+      return ErrorResponse.new "Invalid Ruby Code: method checking failed / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}", 500
+    end
+
+    RackHelper.log "TRACK-B"
+    # Save config parameters to filesystem so that later /run can use this
+    File.write Filepath::CONFIG, {:main=>main, :name=>name}.to_json
+
+    # Proceed with the next step
+    SuccessResponse.new({'OK'=>true})
+  end
+
+  private
+    def valid_code?(path)
+      system("ruby -e 'RubyVM::InstructionSequence.compile_file(\"#{path}\")' 2> #{Filepath::ERR} 1> #{Filepath::OUT}")
+    rescue
+      false
+    end
+
+    def unzip(zipfile_path, destination_folder)
+      Zip::File.open(zipfile_path) do |zip|
+        zip.each do |file|
+          zip.extract(file, destination_folder + file.name)
+        end
+      end
+      true
+    rescue
+      false
+    end
+end
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/middleware/base.rb b/core/ruby2.5Action/rackapp/middleware/base.rb
new file mode 100644
index 0000000..d362d66
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/middleware/base.rb
@@ -0,0 +1,5 @@
+class MiddlewareBase
+  def initialize(app)
+    @app = app
+  end
+end  
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/middleware/post_method_validation.rb b/core/ruby2.5Action/rackapp/middleware/post_method_validation.rb
new file mode 100644
index 0000000..8de8dba
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/middleware/post_method_validation.rb
@@ -0,0 +1,11 @@
+require "#{__dir__}/base.rb"
+
+class HTTPPostMethodValidation < MiddlewareBase
+  def call(env)
+    if Rack::Request.new(env).request_method == 'POST' then
+      @app.call(env)
+    else
+      Rack::Response.new 'Something went wrong with the request', 500
+    end
+  end
+end  
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
new file mode 100644
index 0000000..92f57ad
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
@@ -0,0 +1,14 @@
+require "#{__dir__}/base.rb"
+
+class SentinelHandler < MiddlewareBase
+  def call(env)
+    response = @app.call(env)
+    RackHelper.log response.status.to_json
+    if !(env['REQUEST_PATH'] == '/init' && response.status == 200) then
+      puts response.body if response.status!=200
+      puts "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"
+      warn "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"
+    end
+    response
+  end
+end
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/response/error.rb b/core/ruby2.5Action/rackapp/response/error.rb
new file mode 100644
index 0000000..f7c9365
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/response/error.rb
@@ -0,0 +1,6 @@
+class ErrorResponse < Rack::Response
+  def initialize(body = [], status = 500, header = {})
+    RackHelper.log body.to_s + caller.to_json
+    super({:error=>body}.to_json, status, header.merge({'Content-Type' => 'application/json'}))
+  end
+end 
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/response/success.rb b/core/ruby2.5Action/rackapp/response/success.rb
new file mode 100644
index 0000000..9d3efb2
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/response/success.rb
@@ -0,0 +1,5 @@
+class SuccessResponse < Rack::Response
+  def initialize(body = [], status = 200, header = {})
+    super body.to_json, status, header.merge({'Content-Type' => 'application/json'})
+  end
+end  
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/run.rb b/core/ruby2.5Action/rackapp/run.rb
new file mode 100644
index 0000000..9735639
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/run.rb
@@ -0,0 +1,53 @@
+require "#{__dir__}/response/success.rb"
+require "#{__dir__}/response/error.rb"
+require "#{__dir__}/filepath.rb"
+
+class RunApp
+  def call(env) 
+    RackHelper.log "YES"
+    if !File.exist? Filepath::ENTRYPOINT then
+      return ErrorResponse.new 'Invalid Action: no action file found', 500
+    end
+
+    # Set environment variables
+    RackHelper.log "NO"
+    body = Rack::Request.new(env).body.read
+    data = JSON.parse(body) || {}
+    env = {'BUNDLE_GEMFILE' => Filepath::PROGRAM_DIR + 'Gemfile'}
+    ['api_key', 'namespace', 'action_name', 'activation_id', 'deadline'].each{|e|
+      env["__OW_#{e.upcase}"] = data[e] if data[e] && data[e].is_a?(String)
+    }
+
+    # Save parameter values to file in order to let runner.rb read this later
+    File.write Filepath::PARAM, data['value'].to_json
+
+    # Execute the action with given parameters
+    RackHelper.log File.read(Filepath::PARAM)
+    if system(env, "bundle exec ruby -r #{Filepath::ENTRYPOINT} #{Filepath::RACKAPP_DIR}runner.rb | tee #{Filepath::OUT}") then
+      if File.exist? Filepath::RESULT then
+        result = File.read(Filepath::RESULT)
+        RackHelper.log result
+        if valid_json?(result) then
+          RackHelper.log "B"
+          SuccessResponse.new(JSON.parse(result))
+        else
+          RackHelper.log "C"
+          warn "Result must be an array but has type '#{result.class.to_s}': #{result}"
+          ErrorResponse.new 'The action did not return a dictionary.', 502
+        end
+      else
+        ErrorResponse.new 'Invalid Action: An error occurred running the action', 502
+      end
+    else
+      RackHelper.log File.read(Filepath::OUT) || "(No stdout found)"
+      ErrorResponse.new "Invalid Action: the execution was not successful. / #{File.read(Filepath::OUT)}}", 502
+    end
+  end
+
+  private
+    def valid_json?(json)
+      JSON.parse(json).class == Hash
+    rescue
+      false
+    end
+end
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/runner.rb b/core/ruby2.5Action/rackapp/runner.rb
new file mode 100644
index 0000000..5f607da
--- /dev/null
+++ b/core/ruby2.5Action/rackapp/runner.rb
@@ -0,0 +1,9 @@
+#!/usr/bin/ruby
+
+require 'json'
+require "#{__dir__}/filepath.rb"
+
+include Filepath
+config = JSON.parse(File.read(CONFIG))
+param = JSON.parse(File.read(PARAM))
+File.write RESULT, method(config["main"]).call(param).to_json
diff --git a/gradle/README.md b/gradle/README.md
new file mode 100644
index 0000000..14842f1
--- /dev/null
+++ b/gradle/README.md
@@ -0,0 +1,64 @@
+<!--
+#
+# 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.
+#
+-->
+
+# Gradle
+
+Gradle is used to build OpenWhisk. It does not need to be pre-installed as it installs itself using the [Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html). To use it without installing, simply invoke the `gradlew` command at the root of the repository. You can also install `gradle` via [`apt`](http://linuxg.net/how-to-install-gradle-2-1-on-ubuntu-14-10-ubuntu-14-04-ubuntu-12-04-and-derivatives/) on Ubuntu or [`brew`](http://www.brewformulas.org/Gradle) on Mac [...]
+
+## Usage
+
+In general, project level properties are set via `-P{propertyName}={propertyValue}`. A task is called via `gradle {taskName}` and a subproject task is called via `gradle :path:to:subproject:{taskName}`. To run tasks in parallel, use the `--parallel` flag (**Note:** It's an incubating feature and might break stuff).
+
+### Build
+
+To build all Docker images use `gradle distDocker` at the top level project, to build a specific component use `gradle :core:controller:distDocker`.
+
+Project level options that can be used on `distDocker`:
+
+- `dockerImageName` (*required*): The name of the image to build (e.g. whisk/controller)
+- `dockerHost` (*optional*): The docker host to run commands on, default behaviour is docker's own `DOCKER_HOST` environment variable
+- `dockerRegistry` (*optional*): The registry to push to
+- `dockerImageTag` (*optional*, default 'latest'): The tag for the image
+- `dockerTimeout` (*optional*, default 240): Timeout for docker operations in seconds
+- `dockerRetries` (*optional*, default 3): How many times to retry docker operations
+- `dockerBinary` (*optional*, default `docker`): The binary to execute docker commands
+
+### Test
+
+To run tests one uses the `test` task. OpenWhisk consolidates tests into a single `tests` project. Hence the command to run all tests is `gradle :tests:test`.
+
+It is possible to run specific tests using [Gradle testfilters](https://docs.gradle.org/current/userguide/java_plugin.html#test_filtering). For example `gradle :tests:test --tests "your.package.name.TestClass.evenMethodName"`. Wildcard `*` may be used anywhere.
+
+## Build your own `build.gradle`
+In Gradle, most of the tasks we use are default tasks provided by plugins in Gradle. The [`scala` Plugin](https://docs.gradle.org/current/userguide/scala_plugin.html) for example includes tasks, that are needed to build Scala projects. Moreover, Gradle is aware of *Applications*. The [`application` Plugin](https://docs.gradle.org/current/userguide/application_plugin.html) provides tasks that are required to distribute a self-contained application. When `application` and `scala` are used  [...]
+
+In OpenWhisk, we want to distribute our application via Docker images. Hence we wrote a "plugin" that creates the task `distDocker`. That task will build an image from the `Dockerfile` that is located next to the `build.gradle` it is called from, for example Controller's `Dockerfile` and `build.gradle` are both located at `core/controller`.
+
+If you want to create a new `build.gradle` for your component, simply put the `Dockerfile` right next to it and include `docker.gradle` by using
+
+```
+ext.dockerImageName = 'openwwhisk/{IMAGENAME}'
+apply from: 'path/to/docker.gradle'
+```
+
+If your component needs to be build before you can build the image, make `distDocker` depend on any task needed to run before it, for example:
+
+```
+distDocker.dependsOn ':common:scala:distDocker', 'distTar'
+```
diff --git a/gradle/docker.gradle b/gradle/docker.gradle
new file mode 100644
index 0000000..f716c7b
--- /dev/null
+++ b/gradle/docker.gradle
@@ -0,0 +1,99 @@
+import groovy.time.*
+
+/**
+ * Utility to build docker images based in gradle projects
+ *
+ * This extends gradle's 'application' plugin logic with a 'distDocker' task which builds
+ * a docker image from the Dockerfile of the project that applies this file. The image
+ * is automatically tagged and pushed if a tag and/or a registry is given.
+ *
+ * Parameters that can be set on project level:
+ * - dockerImageName (required): The name of the image to build (e.g. controller)
+ * - dockerRegistry (optional): The registry to push to
+ * - dockerImageTag (optional, default 'latest'): The tag for the image
+ * - dockerImagePrefix (optional, default 'whisk'): The prefix for the image,
+ *       'controller' becomes 'whisk/controller' per default
+ * - dockerTimeout (optional, default 840): Timeout for docker operations in seconds
+ * - dockerRetries (optional, default 3): How many times to retry docker operations
+ * - dockerBinary (optional, default 'docker'): The binary to execute docker commands
+ * - dockerBuildArgs (options, default ''): Project specific custom docker build arguments
+ * - dockerHost (optional): The docker host to run commands on, default behaviour is
+ *       docker's own DOCKER_HOST environment variable
+ */
+
+ext {
+    dockerRegistry = project.hasProperty('dockerRegistry') ? dockerRegistry + '/' : ''
+    dockerImageTag = project.hasProperty('dockerImageTag') ? dockerImageTag : 'latest'
+    dockerImagePrefix = project.hasProperty('dockerImagePrefix') ? dockerImagePrefix : 'whisk'
+    dockerTimeout = project.hasProperty('dockerTimeout') ? dockerTimeout.toInteger() : 840
+    dockerRetries = project.hasProperty('dockerRetries') ? dockerRetries.toInteger() : 3
+    dockerBinary = project.hasProperty('dockerBinary') ? [dockerBinary] : ['docker']
+    dockerBuildArg = ['build']
+}
+ext.dockerTaggedImageName = dockerRegistry + dockerImagePrefix + '/' + dockerImageName + ':' + dockerImageTag
+
+if(project.hasProperty('dockerHost')) {
+    dockerBinary += ['--host', project.dockerHost]
+}
+
+if(project.hasProperty('dockerBuildArgs')) {
+    dockerBuildArgs.each { arg  ->
+        dockerBuildArg += ['--build-arg', arg]
+    }
+}
+
+task distDocker {
+    doLast {
+        def start = new Date()
+        def cmd = dockerBinary + dockerBuildArg + ['-t', dockerImageName, project.buildscript.sourceFile.getParentFile().getAbsolutePath()]
+        retry(cmd, dockerRetries, dockerTimeout)
+        println("Building '${dockerImageName}' took ${TimeCategory.minus(new Date(), start)}")
+    }
+}
+task tagImage {
+    doLast {
+        def versionString = (dockerBinary + ['-v']).execute().text
+        def matched = (versionString =~ /(\d+)\.(\d+)\.(\d+)/)
+
+        def major = matched[0][1] as int
+        def minor = matched[0][2] as int
+
+        def dockerCmd = ['tag']
+        if(major == 1 && minor < 12) {
+            dockerCmd += ['-f']
+        }
+        retry(dockerBinary + dockerCmd + [dockerImageName, dockerTaggedImageName], dockerRetries, dockerTimeout)
+    }
+}
+
+task pushImage {
+    doLast {
+        def cmd = dockerBinary + ['push', dockerTaggedImageName]
+        retry(cmd, dockerRetries, dockerTimeout)
+    }
+}
+pushImage.dependsOn tagImage
+pushImage.onlyIf { dockerRegistry != '' }
+distDocker.finalizedBy pushImage
+
+def retry(cmd, retries, timeout) {
+    println("${new Date()}: Executing '${cmd.join(" ")}'")
+    def proc = cmd.execute()
+    proc.consumeProcessOutput(System.out, System.err)
+    proc.waitForOrKill(timeout * 1000)
+    if(proc.exitValue() != 0) {
+        def message = "${new Date()}: Command '${cmd.join(" ")}' failed with exitCode ${proc.exitValue()}"
+        if(proc.exitValue() == 143) { // 143 means the process was killed (SIGTERM signal)
+            message = "${new Date()}: Command '${cmd.join(" ")}' was killed after ${timeout} seconds"
+        }
+
+        if(retries > 1) {
+            println("${message}, ${retries-1} retries left, retrying...")
+            retry(cmd, retries-1, timeout)
+        }
+        else {
+            println("${message}, no more retries left, aborting...")
+            throw new GradleException(message)
+        }
+    }
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..f16d266
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100755
index 0000000..f955316
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..92db886
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,19 @@
+include 'tests'
+
+include 'core:ruby2.5Action'
+
+rootProject.name = 'runtime-ruby'
+
+gradle.ext.openwhisk = [
+        version: '1.0.0-SNAPSHOT'
+]
+
+gradle.ext.scala = [
+    version: '2.11.8',
+    compileFlags: ['-feature', '-unchecked', '-deprecation', '-Xfatal-warnings', '-Ywarn-unused-import']
+]
+
+gradle.ext.scalafmt = [
+    version: '1.5.0',
+    config: new File(rootProject.projectDir, '.scalafmt.conf')
+]
diff --git a/sshconfig b/sshconfig
new file mode 100644
index 0000000..95d1af6
--- /dev/null
+++ b/sshconfig
@@ -0,0 +1,12 @@
+Host default
+  HostName 127.0.0.1
+  User vagrant
+  Port 2222
+  UserKnownHostsFile /dev/null
+  StrictHostKeyChecking no
+  PasswordAuthentication no
+  IdentityFile /Users/ksawada/src/github/openwhisk/tools/vagrant/.vagrant/machines/default/virtualbox/private_key
+  IdentitiesOnly yes
+  LogLevel FATAL
+  ForwardAgent yes
+
diff --git a/tests/.pydevproject b/tests/.pydevproject
new file mode 100644
index 0000000..40e9f40
--- /dev/null
+++ b/tests/.pydevproject
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+</pydev_project>
diff --git a/tests/build.gradle b/tests/build.gradle
new file mode 100644
index 0000000..1ae5a4b
--- /dev/null
+++ b/tests/build.gradle
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+apply plugin: 'scala'
+apply plugin: 'eclipse'
+compileTestScala.options.encoding = 'UTF-8'
+
+repositories {
+    mavenCentral()
+    mavenLocal()
+}
+
+tasks.withType(Test) {
+    testLogging {
+        events "passed", "skipped", "failed"
+        showStandardStreams = true
+        exceptionFormat = 'full'
+    }
+    outputs.upToDateWhen { false } // force tests to run every time
+}
+
+dependencies {
+    compile "org.scala-lang:scala-library:${gradle.scala.version}"
+    compile "org.apache.openwhisk:openwhisk-tests:${gradle.openwhisk.version}:tests"
+    compile "org.apache.openwhisk:openwhisk-tests:${gradle.openwhisk.version}:test-sources"
+}
+
+tasks.withType(ScalaCompile) {
+    scalaCompileOptions.additionalParameters = gradle.scala.compileFlags
+}
diff --git a/tests/src/test/resources/application.conf b/tests/src/test/resources/application.conf
new file mode 100644
index 0000000..759f063
--- /dev/null
+++ b/tests/src/test/resources/application.conf
@@ -0,0 +1,8 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more contributor
+# license agreements; and to You under the Apache License, Version 2.0.
+
+whisk.spi {
+  SimpleSpi = whisk.spi.SimpleSpiImpl
+  MissingSpi = whisk.spi.MissingImpl
+  MissingModule = missing.module
+}
diff --git a/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
new file mode 100644
index 0000000..c581273
--- /dev/null
+++ b/tests/src/test/scala/actionContainers/Ruby25ActionContainerTests.scala
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package runtime.actionContainers
+
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+import common.WskActorSystem
+import actionContainers.{ActionContainer, BasicActionRunnerTests}
+import actionContainers.ActionContainer.withContainer
+import actionContainers.ResourceHelpers.ZipBuilder
+import spray.json._
+
+@RunWith(classOf[JUnitRunner])
+class Ruby25ActionContainerTests extends BasicActionRunnerTests with WskActorSystem {
+  // note: "out" will not be empty as the Webrick outputs a message during the boot and after the boot
+  val enforceEmptyOutputStream = false
+
+  lazy val ruby25ContainerImageName = "action-ruby-v2.5"
+
+  override def withActionContainer(env: Map[String, String] = Map.empty)(code: ActionContainer => Unit) = {
+    withContainer(ruby25ContainerImageName, env)(code)
+  }
+
+  def withRuby25Container(code: ActionContainer => Unit) = withActionContainer()(code)
+
+  behavior of ruby25ContainerImageName
+
+  testEcho(Seq {
+    (
+      "RUBY",
+      """
+          |def main(args)
+          |  puts 'hello stdout'
+          |  warn 'hello stderr'
+          |  #require 'net/http'; require 'uri'; res = Net::HTTP.post_form(URI.parse('http://remore-mockbin.herokuapp.com/bin/38e74975-104b-4733-9d90-834aaf14f909'), {'q'=>args, 'max'=>args.class.to_s})
+          |  args
+          |end
+          """.stripMargin)
+  })
+
+  testNotReturningJson("""
+        |def main(args)
+        |  "not a json object"
+        |end
+        """.stripMargin)
+
+  testUnicode(Seq {
+    (
+      "RUBY",
+      """
+         |def main(args)
+         |  str = args['delimiter'] + " ☃ " + args['delimiter']
+         |  print str + "\n"
+         |  {"winter" => str}
+         |end
+         """.stripMargin.trim)
+  })
+
+  testEnv(
+    Seq {
+      (
+        "RUBY",
+        """
+         |def main(args)
+         |  {
+         |       "env" => ENV,
+         |       "api_host" => ENV['__OW_API_HOST'],
+         |       "api_key" => ENV['__OW_API_KEY'],
+         |       "namespace" => ENV['__OW_NAMESPACE'],
+         |       "action_name" => ENV['__OW_ACTION_NAME'],
+         |       "activation_id" => ENV['__OW_ACTIVATION_ID'],
+         |       "deadline" => ENV['__OW_DEADLINE']
+         |  }
+         |end
+         """.stripMargin.trim)
+    },
+    enforceEmptyOutputStream)
+
+  it should "fail to initialize with bad code" in {
+    val (out, err) = withRuby25Container { c =>
+      val code = """
+                | 10 PRINT "Hello world!"
+                | 20 GOTO 10
+            """.stripMargin
+
+      val (initCode, error) = c.init(initPayload(code))
+      initCode should not be (200)
+      error shouldBe a[Some[_]]
+      error.get shouldBe a[JsObject]
+      error.get.fields("error").toString should include("failed to parse the input code")
+    }
+
+    // Somewhere, the logs should mention an error occurred.
+    checkStreams(out, err, {
+      case (o, e) =>
+        (o + e).toLowerCase should include("invalid")
+        (o + e).toLowerCase should include("parse")
+    })
+  }
+
+  it should "fail to initialize with no code" in {
+    val (out, err) = withRuby25Container { c =>
+      val code = ""
+
+      val (initCode, error) = c.init(initPayload(code))
+
+      initCode should not be (200)
+      error shouldBe a[Some[_]]
+      error.get shouldBe a[JsObject]
+      error.get.fields("error").toString should include("method checking failed")
+    }
+  }
+
+  it should "return some error on action error" in {
+    val (out, err) = withRuby25Container { c =>
+      val code = """
+                | def main(args)
+                |   raise Exception.new("nooooo")
+                | end
+            """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runCode should not be (200)
+
+      runRes shouldBe defined
+      runRes.get.fields.get("error") shouldBe defined
+    // runRes.get.fields("error").toString.toLowerCase should include("nooooo")
+    }
+
+    // Somewhere, the logs should be the error text
+    checkStreams(out, err, {
+      case (o, e) =>
+        (o + e).toLowerCase should include("nooooo")
+    })
+
+  }
+
+  it should "support application errors" in {
+    withRuby25Container { c =>
+      val code = """
+                | def main(args)
+                |   { "error" => "sorry" }
+                | end
+            """.stripMargin;
+
+      val (initCode, error) = c.init(initPayload(code))
+      initCode should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runCode should be(200) // action writer returning an error is OK
+
+      runRes shouldBe defined
+      runRes.get.fields.get("error") shouldBe defined
+      runRes.get.fields("error").toString.toLowerCase should include("sorry")
+    }
+  }
+
+  it should "fail gracefully when an action has a TypeError exception" in {
+    val (out, err) = withRuby25Container { c =>
+      val code = """
+                | def main(args)
+                |   eval "class ENV\nend"
+                |   { "hello" => "world" }
+                | end
+            """.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
+      runRes.get.fields("error").toString should include("An error occurred running the action")
+    }
+
+    // Somewhere, the logs should be the error text
+    checkStreams(out, err, {
+      case (o, e) =>
+        (o + e).toLowerCase should include("typeerror")
+    })
+  }
+
+  it should "support the documentation examples (1)" in {
+    val (out, err) = withRuby25Container { c =>
+      val code = """
+                | def main(params)
+                |   if (params['payload'] == 0) then
+                |     return {}
+                |   elsif params['payload'] == 1 then
+                |     return {'payload' => 'Hello, World!'} # indicates normal completion
+                |   elsif params['payload'] == 2 then
+                |     return {'error' => 'payload must be 0 or 1'}  # indicates abnormal completion
+                |   end
+                | end
+            """.stripMargin
+
+      c.init(initPayload(code))._1 should be(200)
+
+      val (c1, r1) = c.run(runPayload(JsObject("payload" -> JsNumber(0))))
+      val (c2, r2) = c.run(runPayload(JsObject("payload" -> JsNumber(1))))
+      val (c3, r3) = c.run(runPayload(JsObject("payload" -> JsNumber(2))))
+
+      c1 should be(200)
+      r1 should be(Some(JsObject()))
+
+      c2 should be(200)
+      r2 should be(Some(JsObject("payload" -> JsString("Hello, World!"))))
+
+      c3 should be(200) // application error, not container or system
+      r3.get.fields.get("error") shouldBe Some(JsString("payload must be 0 or 1"))
+    }
+  }
+
+  it should "have mechanize and activesupport gems available" in {
+    // GIVEN that it should "error when requiring a non-existent package" (see test above for this)
+    val (out, err) = withRuby25Container { c =>
+      val code = """
+                | require 'mechanize'
+                | require 'active_support'
+                | def main(args)
+                |   Mechanize.class
+                |   ActiveSupport.class
+                |   {}
+                | end
+            """.stripMargin
+
+      val (initCode, _) = c.init(initPayload(code))
+
+      initCode should be(200)
+
+      // WHEN I run an action that calls a Guzzle & a Uuid method
+      val (runCode, out) = c.run(runPayload(JsObject()))
+
+      // THEN it should pass only when these packages are available
+      runCode should be(200)
+    }
+  }
+
+  it should "support large-ish actions" in {
+    val thought = " I took the one less traveled by, and that has made all the difference."
+    val assignment = "    x = \"" + thought + "\";\n"
+
+    val code = """
+            | def main(args)
+            |   x = "hello"
+            """.stripMargin + (assignment * 7000) + """
+            |   x = "world"
+            |   { "message" => x }
+            | end
+            """.stripMargin
+
+    // Lest someone should make it too easy.
+    code.length should be >= 500000
+
+    val (out, err) = withRuby25Container { c =>
+      c.init(initPayload(code))._1 should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+
+      runCode should be(200)
+      runRes.get.fields.get("message") shouldBe defined
+      runRes.get.fields.get("message") shouldBe Some(JsString("world"))
+    }
+  }
+
+ val exampleOutputDotRuby: String = """
+        | def output(data)
+        |   {'result' => data}
+        | end
+    """.stripMargin
+
+  it should "support zip-encoded packages" in {
+    val srcs = Seq(
+      Seq("output.rb") -> exampleOutputDotRuby,
+      Seq("main.rb") -> """
+                | require __dir__ + '/output.rb'
+                | def main(args)
+                |   name = args['name'] || 'stranger'
+                |   output(name)
+                | end
+            """.stripMargin)
+
+    val code = ZipBuilder.mkBase64Zip(srcs)
+
+    val (out, err) = withRuby25Container { c =>
+      c.init(initPayload(code))._1 should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+
+      runCode should be(200)
+      runRes.get.fields.get("result") shouldBe defined
+      runRes.get.fields.get("result") shouldBe Some(JsString("stranger"))
+    }
+  }
+
+  it should "fail gracefully on invalid zip files" in {
+    // Some text-file encoded to base64.
+    val code = "Q2VjaSBuJ2VzdCBwYXMgdW4gemlwLgo="
+
+    val (out, err) = withRuby25Container { c =>
+      val (initCode, error) = c.init(initPayload(code))
+      initCode should not be (200)
+      error shouldBe a[Some[_]]
+      error.get shouldBe a[JsObject]
+      error.get.fields("error").toString should include("failed to open zip file")
+    }
+
+    // Somewhere, the logs should mention the failure
+    checkStreams(out, err, {
+      case (o, e) =>
+        (o + e).toLowerCase should include("error")
+        (o + e).toLowerCase should include("failed to open zip file")
+    })
+  }
+
+  it should "fail gracefully on valid zip files that are not actions" in {
+    val srcs = Seq(Seq("hello") -> """
+                | Hello world!
+            """.stripMargin)
+
+    val code = ZipBuilder.mkBase64Zip(srcs)
+
+    val (out, err) = withRuby25Container { c =>
+      c.init(initPayload(code))._1 should not be (200)
+    }
+
+    checkStreams(out, err, {
+      case (o, e) =>
+        (o + e).toLowerCase should include("error")
+        (o + e).toLowerCase should include("zipped actions must contain main.rb at the root.")
+    })
+  }
+
+  it should "fail gracefully on valid zip files with invalid code in main.rb" in {
+    val (out, err) = withRuby25Container { c =>
+      val srcs = Seq(Seq("main.rb") -> """
+                    | 10 PRINT "Hello world!"
+                    | 20 GOTO 10
+                """.stripMargin)
+
+      val code = ZipBuilder.mkBase64Zip(srcs)
+
+      val (initCode, error) = c.init(initPayload(code))
+      initCode should not be (200)
+      error shouldBe a[Some[_]]
+      error.get shouldBe a[JsObject]
+      error.get.fields("error").toString should include("failed to parse the input code")
+    }
+
+    // Somewhere, the logs should mention an error occurred.
+    checkStreams(out, err, {
+      case (o, e) =>
+        (o + e).toLowerCase should include("invalid")
+        (o + e).toLowerCase should include("parse")
+    })
+  }
+
+  it should "support actions using non-default entry point" in {
+    val (out, err) = withRuby25Container { c =>
+      val code = """
+            | def niam(args)
+            |   { :result => "it works" }
+            | end
+            """.stripMargin
+
+      c.init(initPayload(code, main = "niam"))._1 should be(200)
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runRes.get.fields.get("result") shouldBe Some(JsString("it works"))
+    }
+  }
+
+  it should "support zipped actions using non-default entry point" in {
+    val srcs = Seq(Seq("main.rb") -> """
+                | def niam(args)
+                |   { :result => "it works" }
+                | end
+            """.stripMargin)
+
+    val code = ZipBuilder.mkBase64Zip(srcs)
+
+    withRuby25Container { c =>
+      c.init(initPayload(code, main = "niam"))._1 should be(200)
+
+      val (runCode, runRes) = c.run(runPayload(JsObject()))
+      runRes.get.fields.get("result") shouldBe Some(JsString("it works"))
+    }
+  }
+
+}


[incubator-openwhisk-runtime-ruby] 10/19: Make tools/travis/+.sh executable

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8dc9b29219ad36aebb0a576f83c1b1ed5e90534e
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 21:16:17 2018 +0900

    Make tools/travis/+.sh executable
---
 tools/travis/build.sh   | 0
 tools/travis/publish.sh | 0
 tools/travis/setup.sh   | 0
 tools/travis/test.sh    | 0
 4 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/tools/travis/build.sh b/tools/travis/build.sh
old mode 100644
new mode 100755
diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
old mode 100644
new mode 100755
diff --git a/tools/travis/setup.sh b/tools/travis/setup.sh
old mode 100644
new mode 100755
diff --git a/tools/travis/test.sh b/tools/travis/test.sh
old mode 100644
new mode 100755


[incubator-openwhisk-runtime-ruby] 12/19: Fix an error in publish.sh

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a81f0d46c102d4763438407558f657fe6d7fffe9
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Fri Jul 13 23:13:25 2018 +0900

    Fix an error in publish.sh
---
 tools/travis/publish.sh | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
old mode 100755
new mode 100644
index 4ff9ec3..78398f9
--- a/tools/travis/publish.sh
+++ b/tools/travis/publish.sh
@@ -27,15 +27,9 @@ WHISKDIR="$ROOTDIR/../openwhisk"
 export OPENWHISK_HOME=$WHISKDIR
 
 IMAGE_PREFIX=$1
-RUNTIME_VERSION=$2
+RUNTIME=$2
 IMAGE_TAG=$3
 
-if [ ${RUNTIME_VERSION} == "2" ]; then
-  RUNTIME="python2Action"
-elif [ ${RUNTIME_VERSION} == "3" ]; then
-  RUNTIME="pythonAction"
-fi
-
 if [[ ! -z ${DOCKER_USER} ]] && [[ ! -z ${DOCKER_PASSWORD} ]]; then
 docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 fi


[incubator-openwhisk-runtime-ruby] 02/19: fixed a few errors and typos

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f46575c16d58c64efa843e0d67f84a396c9fd185
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Tue Jun 5 21:27:03 2018 +0900

    fixed a few errors and typos
---
 README.md                                          | 89 ++++++++++++++++++++++
 core/ruby2.5Action/config.ru                       | 50 ------------
 core/ruby2.5Action/rackapp/init.rb                 | 38 ++++-----
 .../rackapp/middleware/sentinel_handler.rb         |  1 -
 core/ruby2.5Action/rackapp/response/error.rb       |  1 -
 core/ruby2.5Action/rackapp/run.rb                  | 23 +++---
 6 files changed, 114 insertions(+), 88 deletions(-)

diff --git a/README.md b/README.md
index e69de29..5e25b9e 100644
--- a/README.md
+++ b/README.md
@@ -0,0 +1,89 @@
+# Apache OpenWhisk runtimes for Ruby
+
+### Give it a try today
+To use as a docker action
+```
+wsk action update myAction my_action.rb --docker openwhisk/action-ruby-v2.5
+```
+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 my_action.rb --kind ruby:2.5
+```
+
+### Local development
+```
+./gradlew core:ruby2.5Action:distDocker
+```
+This will produce the image `whisk/action-ruby-v2.5`
+
+Build and Push image
+```
+docker login
+./gradlew core:ruby2.5Action:distDocker -PdockerImagePrefix=$prefix-user -PdockerRegistry=docker.io
+```
+
+Deploy OpenWhisk using ansible environment that contains the kind `ruby:2.5`
+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.
+
+Redeploy OpenWhisk
+```
+cd $OPENWHISK_HOME/ansible
+ANSIBLE_CMD="ansible-playbook -i ${ROOTDIR}/ansible/environments/local"
+$ANSIBLE_CMD setup.yml
+$ANSIBLE_CMD couchdb.yml
+$ANSIBLE_CMD initdb.yml
+$ANSIBLE_CMD wipe.yml
+$ANSIBLE_CMD openwhisk.yml
+```
+
+Or you can use `wskdev` and create a soft link to the target ansible environment, for example:
+```
+ln -s ${ROOTDIR}/ansible/environments/local ${OPENWHISK_HOME}/ansible/environments/local-ruby
+wskdev fresh -t local-ruby
+```
+
+To use as docker action push to your own dockerhub account
+```
+docker tag whisk/ruby2.5Action $user_prefix/action-ruby-v2.5
+docker push $user_prefix/action-ruby-v2.5
+```
+Then create the action using your the image from dockerhub
+```
+wsk action update myAction my_action.rb --docker $user_prefix/action-ruby-v2.5
+```
+The `$user_prefix` is usually your dockerhub user id.
+
+### Testing
+Install dependencies from the root directory on $OPENWHISK_HOME repository
+```
+./gradlew install
+```
+
+Using gradle for the ActionContainer tests you need to use a proxy if running on Mac, if Linux then don't use proxy options
+You can pass the flags `-Dhttp.proxyHost=localhost -Dhttp.proxyPort=3128` directly in gradle command.
+Or save in your `$HOME/.gradle/gradle.properties`
+```
+systemProp.http.proxyHost=localhost
+systemProp.http.proxyPort=3128
+```
+Using gradle to run all tests
+```
+./gradlew :tests:test
+```
+Using gradle to run some tests
+```
+./gradlew :tests:test --tests *ActionContainerTests*
+```
+Using IntelliJ:
+- Import project as gradle project.
+- Make sure working directory is root of the project/repo
+- Add the following Java VM properties in ScalaTests Run Configuration, easiest is to change the Defaults for all ScalaTests to use this VM properties
+```
+-Dhttp.proxyHost=localhost
+-Dhttp.proxyPort=3128
+```
diff --git a/core/ruby2.5Action/config.ru b/core/ruby2.5Action/config.ru
index 6b478fc..93c460d 100644
--- a/core/ruby2.5Action/config.ru
+++ b/core/ruby2.5Action/config.ru
@@ -4,40 +4,6 @@ require 'rubygems'
 require 'json'
 require 'zip'
 require 'base64'
-
-#====== For Debugging Purpose Only
-module RackHelper
-  require 'uri'
-  require 'net/http'
-  class << self
-    def _p(name, value)
-      "#{name}: #{value}\n\n-------\n"
-    end
-
-    def log(value)
-      url = URI("http://SOME_URL_SUCH_AS_MOCKBIN/")
-      http = Net::HTTP.new(url.host, url.port)
-
-      req = Net::HTTP::Post.new(url)
-      req["accept"] = 'application/json'
-      req["content-type"] = 'application/x-www-form-urlencoded'
-      req.body = value
-      response = http.request(req)
-    end
-
-    def debug(env)
-      request = Rack::Request.new(env)
-      log _p(:ENV, ENV.to_a) +
-        _p(:request_params, request.params.to_a) + 
-        _p(:request_env, request.env) + 
-        _p(:request_POST, request.POST) + 
-        _p(:body, request.body.read)
-    end
-
-  end
-end
-#====== For Debugging Purpose Only
-
 require "#{__dir__}/rackapp/middleware/post_method_validation.rb"
 require "#{__dir__}/rackapp/middleware/sentinel_handler.rb"
 require "#{__dir__}/rackapp/init.rb"
@@ -47,26 +13,10 @@ rackapp = Rack::Builder.app do
   use HTTPPostMethodValidation
   use SentinelHandler
 
-  #  {
-  #    "value":{
-  #      "name":   "myAction",
-  #      "binary": false,
-  #      "main":   "main",
-  #      "code":   "def main(params) {\\n  {payload: \\\"length = \\\" + params.to_s}\\n}\\n\"
-  #    }
-  #  }
   map '/init' do
     run InitApp.new
   end
 
-  #  {
-  #    "activation_id":    "91f9fa332a424e35b9fa332a423e35fd",
-  #    "action_name":      "/guest/myAction",
-  #    "deadline":         "1526980345727",
-  #    "api_key":          "23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP",
-  #    "value":            {\"message\":\"hello\"},
-  #    "namespace":        "guest"
-  #  }
   map "/run" do
     run RunApp.new
   end
diff --git a/core/ruby2.5Action/rackapp/init.rb b/core/ruby2.5Action/rackapp/init.rb
index 3f85770..d5316e8 100644
--- a/core/ruby2.5Action/rackapp/init.rb
+++ b/core/ruby2.5Action/rackapp/init.rb
@@ -3,11 +3,11 @@ require "#{__dir__}/response/error.rb"
 require "#{__dir__}/filepath.rb"
 
 class InitApp
+  include Filepath
+
   def call(env) 
-    # RackHelper.debug env
     # Expect JSON data input
     body = Rack::Request.new(env).body.read
-    RackHelper.log body
     data = JSON.parse(body)['value'] || {}
     name = data['name'] || ''           # action name
     main = data['main'] || ''           # function to call
@@ -19,50 +19,44 @@ class InitApp
       return ErrorResponse.new 'Invalid Parameters: failed to handle the request', 500
     end
 
-    RackHelper.log env.to_json
-    env = {'BUNDLE_GEMFILE' => Filepath::PROGRAM_DIR + 'Gemfile'}
+    env = {'BUNDLE_GEMFILE' => PROGRAM_DIR + 'Gemfile'}
     if binary then
-      File.write Filepath::TMP_ZIP, Base64.decode64(code)
-      if !unzip(Filepath::TMP_ZIP, Filepath::PROGRAM_DIR) then
+      File.write TMP_ZIP, Base64.decode64(code)
+      if !unzip(TMP_ZIP, PROGRAM_DIR) then
         return ErrorResponse.new 'Invalid Binary: failed to open zip file. Please make sure you have finishied $bundle package successfully.', 500
       end
-      RackHelper.log `ls -alR #{Filepath::PROGRAM_DIR}`
       # Try to resolve dependencies
-      if File.exist?(Filepath::PROGRAM_DIR + 'Gemfile') then
-        if !File.directory?(Filepath::PROGRAM_DIR + 'vendor/cache') then
+      if File.exist?(PROGRAM_DIR + 'Gemfile') then
+        if !File.directory?(PROGRAM_DIR + 'vendor/cache') then
           return ErrorResponse.new 'Invalid Binary: vendor/cache folder is not found. Please make sure you have used valid zip binary.', 200
         end
-        if !system(env, "bundle install --local 2> #{Filepath::ERR} 1> #{Filepath::OUT}") then
-          return ErrorResponse.new "Invalid Binary: failed to resolve dependencies / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}", 500
+        if !system(env, "bundle install --local 2> #{ERR} 1> #{OUT}") then
+          return ErrorResponse.new "Invalid Binary: failed to resolve dependencies / #{File.read(OUT)} / #{File.read(ERR)}", 500
         end
       else
         File.write env['BUNDLE_GEMFILE'], ''  # For better performance, better to remove Gemfile and remove "bundle exec" redundant call when binary=false. To be improved in future.
       end
-      if !File.exist?(Filepath::ENTRYPOINT) then
+      if !File.exist?(ENTRYPOINT) then
         return ErrorResponse.new 'Invalid Ruby Code: zipped actions must contain main.rb at the root.', 500
       end
     else
       # Save the code for future use
-      File.write Filepath::ENTRYPOINT, code
+      File.write ENTRYPOINT, code
       File.write env['BUNDLE_GEMFILE'], ''  # For better performance, better to remove Gemfile and remove "bundle exec" redundant call when binary=false. To be improved in future.
     end
 
     # Check if the ENTRYPOINT code is valid or not
-    RackHelper.log "TRACK-Zero"
-    if !valid_code?(Filepath::ENTRYPOINT) then
-      RackHelper.log "TRACK-alpha / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}"
+    if !valid_code?(ENTRYPOINT) then
       return ErrorResponse.new 'Invalid Ruby Code: failed to parse the input code', 500
     end
 
-    RackHelper.log "TRACK-A"
     # Check if the method exists as expected
-    if !system(env, "bundle exec ruby -r #{Filepath::ENTRYPOINT} -e \"method(:#{main}) ? true : raise(Exception.new('Error'))\" 2> #{Filepath::ERR} 1> #{Filepath::OUT}") then
-      return ErrorResponse.new "Invalid Ruby Code: method checking failed / #{File.read(Filepath::OUT)} / #{File.read(Filepath::ERR)}", 500
+    if !system(env, "bundle exec ruby -r #{ENTRYPOINT} -e \"method(:#{main}) ? true : raise(Exception.new('Error'))\" 2> #{ERR} 1> #{OUT}") then
+      return ErrorResponse.new "Invalid Ruby Code: method checking failed / #{File.read(OUT)} / #{File.read(ERR)}", 500
     end
 
-    RackHelper.log "TRACK-B"
     # Save config parameters to filesystem so that later /run can use this
-    File.write Filepath::CONFIG, {:main=>main, :name=>name}.to_json
+    File.write CONFIG, {:main=>main, :name=>name}.to_json
 
     # Proceed with the next step
     SuccessResponse.new({'OK'=>true})
@@ -70,7 +64,7 @@ class InitApp
 
   private
     def valid_code?(path)
-      system("ruby -e 'RubyVM::InstructionSequence.compile_file(\"#{path}\")' 2> #{Filepath::ERR} 1> #{Filepath::OUT}")
+      system("ruby -e 'RubyVM::InstructionSequence.compile_file(\"#{path}\")' 2> #{ERR} 1> #{OUT}")
     rescue
       false
     end
diff --git a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
index 92f57ad..3d1d1bf 100644
--- a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
+++ b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
@@ -3,7 +3,6 @@ require "#{__dir__}/base.rb"
 class SentinelHandler < MiddlewareBase
   def call(env)
     response = @app.call(env)
-    RackHelper.log response.status.to_json
     if !(env['REQUEST_PATH'] == '/init' && response.status == 200) then
       puts response.body if response.status!=200
       puts "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"
diff --git a/core/ruby2.5Action/rackapp/response/error.rb b/core/ruby2.5Action/rackapp/response/error.rb
index f7c9365..57d9584 100644
--- a/core/ruby2.5Action/rackapp/response/error.rb
+++ b/core/ruby2.5Action/rackapp/response/error.rb
@@ -1,6 +1,5 @@
 class ErrorResponse < Rack::Response
   def initialize(body = [], status = 500, header = {})
-    RackHelper.log body.to_s + caller.to_json
     super({:error=>body}.to_json, status, header.merge({'Content-Type' => 'application/json'}))
   end
 end 
\ No newline at end of file
diff --git a/core/ruby2.5Action/rackapp/run.rb b/core/ruby2.5Action/rackapp/run.rb
index 9735639..c4699d2 100644
--- a/core/ruby2.5Action/rackapp/run.rb
+++ b/core/ruby2.5Action/rackapp/run.rb
@@ -3,35 +3,31 @@ require "#{__dir__}/response/error.rb"
 require "#{__dir__}/filepath.rb"
 
 class RunApp
+  include Filepath
+  
   def call(env) 
-    RackHelper.log "YES"
-    if !File.exist? Filepath::ENTRYPOINT then
+    if !File.exist? ENTRYPOINT then
       return ErrorResponse.new 'Invalid Action: no action file found', 500
     end
 
     # Set environment variables
-    RackHelper.log "NO"
     body = Rack::Request.new(env).body.read
     data = JSON.parse(body) || {}
-    env = {'BUNDLE_GEMFILE' => Filepath::PROGRAM_DIR + 'Gemfile'}
+    env = {'BUNDLE_GEMFILE' => PROGRAM_DIR + 'Gemfile'}
     ['api_key', 'namespace', 'action_name', 'activation_id', 'deadline'].each{|e|
       env["__OW_#{e.upcase}"] = data[e] if data[e] && data[e].is_a?(String)
     }
 
     # Save parameter values to file in order to let runner.rb read this later
-    File.write Filepath::PARAM, data['value'].to_json
+    File.write PARAM, data['value'].to_json
 
     # Execute the action with given parameters
-    RackHelper.log File.read(Filepath::PARAM)
-    if system(env, "bundle exec ruby -r #{Filepath::ENTRYPOINT} #{Filepath::RACKAPP_DIR}runner.rb | tee #{Filepath::OUT}") then
-      if File.exist? Filepath::RESULT then
-        result = File.read(Filepath::RESULT)
-        RackHelper.log result
+    if system(env, "bundle exec ruby -r #{ENTRYPOINT} #{RACKAPP_DIR}runner.rb | tee #{OUT}") then
+      if File.exist? RESULT then
+        result = File.read(RESULT)
         if valid_json?(result) then
-          RackHelper.log "B"
           SuccessResponse.new(JSON.parse(result))
         else
-          RackHelper.log "C"
           warn "Result must be an array but has type '#{result.class.to_s}': #{result}"
           ErrorResponse.new 'The action did not return a dictionary.', 502
         end
@@ -39,8 +35,7 @@ class RunApp
         ErrorResponse.new 'Invalid Action: An error occurred running the action', 502
       end
     else
-      RackHelper.log File.read(Filepath::OUT) || "(No stdout found)"
-      ErrorResponse.new "Invalid Action: the execution was not successful. / #{File.read(Filepath::OUT)}}", 502
+      ErrorResponse.new "Invalid Action: the execution was not successful. / #{File.read(OUT)}}", 502
     end
   end
 


[incubator-openwhisk-runtime-ruby] 17/19: Add another boundary for sentinel handling to make testInitCannotBeCalledMoreThanOnce work

Posted by ra...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit dc1f9580413009bce6172e75d4eb1e4068f2216d
Author: Kei Sawada <k...@swd.cc>
AuthorDate: Sun Jul 15 01:38:29 2018 +0900

    Add another boundary for sentinel handling to make testInitCannotBeCalledMoreThanOnce work
---
 core/ruby2.5Action/rackapp/init.rb                        | 1 +
 core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/core/ruby2.5Action/rackapp/init.rb b/core/ruby2.5Action/rackapp/init.rb
index 55f7151..4b9dcf4 100644
--- a/core/ruby2.5Action/rackapp/init.rb
+++ b/core/ruby2.5Action/rackapp/init.rb
@@ -8,6 +8,7 @@ class InitApp
   def call(env)
     # Make sure that this action is not initialised more than once
     if File.exist? CONFIG then
+      puts "Error: Cannot initialize the action more than once."
       return ErrorResponse.new 'Cannot initialize the action more than once.', 403
     end
 
diff --git a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
index 3d1d1bf..2161bde 100644
--- a/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
+++ b/core/ruby2.5Action/rackapp/middleware/sentinel_handler.rb
@@ -3,7 +3,7 @@ require "#{__dir__}/base.rb"
 class SentinelHandler < MiddlewareBase
   def call(env)
     response = @app.call(env)
-    if !(env['REQUEST_PATH'] == '/init' && response.status == 200) then
+    if !(env['REQUEST_PATH'] == '/init' && [200,403].include?(response.status)) then
       puts response.body if response.status!=200
       puts "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"
       warn "XXX_THE_END_OF_A_WHISK_ACTIVATION_XXX"