You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ms...@apache.org on 2020/08/30 15:05:18 UTC

[openwhisk-runtime-go] branch master updated: Go 1.13 and 1.15 support with modules, updated examples and documentation (despite the branch name mentioning 1.14) (#128)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new a9f3aa8  Go 1.13  and 1.15 support with modules, updated examples and documentation (despite the branch name mentioning 1.14) (#128)
a9f3aa8 is described below

commit a9f3aa832d742c2fce92c5132ff52a95a6b94bff
Author: Michele Sciabarra <30...@users.noreply.github.com>
AuthorDate: Sun Aug 30 17:05:08 2020 +0200

    Go 1.13  and 1.15 support with modules, updated examples and documentation (despite the branch name mentioning 1.14) (#128)
    
    * updated tests
    
    * adding go1.13 and go1.15
    
    * reworked examples and docs
    
    * support modules
    
    Co-authored-by: rodric rabbah <ro...@gmail.com>
---
 .gitignore                                         |   2 +-
 .travis.yml                                        |   2 +-
 CHANGES.md                                         |   3 +
 docs/ACTION.md                                     |   7 +-
 docs/BUILD.md                                      |  10 +-
 docs/DEPLOY.md                                     | 107 +++-------------
 examples/EXAMPLES.md                               |  27 ++--
 examples/Makefile                                  |  64 +++++-----
 examples/{bash-hello => bash}/Makefile             |  11 +-
 examples/{bash-hello => bash}/hello.sh             |   5 +-
 examples/benchmark/init.sh                         |  20 ---
 examples/golang-hello-vendor/Makefile              |  63 ----------
 examples/golang-hello-vendor/src/hello/Gopkg.lock  |  44 -------
 examples/golang-hello-vendor/src/hello/Gopkg.toml  |  66 ----------
 examples/golang-hello-vendor/src/hello/hello.go    |  43 -------
 .../golang-hello-vendor/src/hello/hello_test.go    |  41 ------
 examples/golang-main-single/main.go                |  31 -----
 examples/golang-main-vendor/src/main/Gopkg.lock    |  25 ----
 examples/golang-main-vendor/src/main/Gopkg.toml    |  66 ----------
 .../{golang-main-vendor => module-main}/Makefile   |  24 ++--
 examples/module-main/go.mod                        |   5 +
 examples/module-main/go.sum                        |  12 ++
 .../src/main => module-main}/main.go               |   2 +-
 .../{golang-main-package => package-main}/Makefile |  17 +--
 examples/package-main/go.mod                       |   7 ++
 examples/package-main/hello/go.mod                 |   3 +
 .../src => package-main}/hello/hello.go            |   2 +-
 .../src => package-main}/hello/hello_test.go       |   2 +-
 .../src => package-main}/main.go                   |   0
 .../{golang-hello-single => single-hello}/Makefile |  11 +-
 .../{golang-hello-single => single-hello}/hello.go |   2 +-
 .../{golang-main-single => single-main}/Makefile   |  11 +-
 examples/{benchmark => single-main}/main.go        |   2 +-
 .../Makefile                                       |   9 +-
 .../src/exec => standalone/exec.go}                |   6 +-
 examples/test.expected                             |  10 ++
 go.mod                                             |   6 +-
 go.sum                                             |  20 +++
 golang1.11/Dockerfile                              |   8 +-
 golang1.12/Dockerfile                              |   8 +-
 {golang1.11 => golang1.13}/Dockerfile              |  38 +++---
 {examples/benchmark => golang1.13}/Makefile        |  41 +++---
 golang1.13/bin/compile                             | 138 +++++++++++++++++++++
 .../src/main/main.go => golang1.13/build.gradle    |  34 ++---
 .../src/exec => golang1.13/lib/launcher.go         |  40 +++---
 {golang1.11 => golang1.15}/Dockerfile              |  38 +++---
 examples/benchmark/main.sh => golang1.15/Makefile  |  35 ++++--
 golang1.15/bin/compile                             | 138 +++++++++++++++++++++
 .../src/main/main.go => golang1.15/build.gradle    |  34 ++---
 .../src/exec => golang1.15/lib/launcher.go         |  40 +++---
 main/proxy.go                                      |   5 +-
 openwhisk/actionProxy.go                           |   9 +-
 openwhisk/actionProxy_test.go                      |   4 +-
 openwhisk/compiler_test.go                         |   4 +
 settings.gradle                                    |   2 +
 .../ActionLoopBasicGo12Tests.scala                 | 115 +----------------
 .../ActionLoopBasicGo13Tests.scala                 |  20 +--
 .../ActionLoopBasicGo15Tests.scala                 |  20 +--
 .../actionContainers/ActionLoopBasicGoTests.scala  |  36 +++---
 .../ActionLoopGo12ContainerTests.scala             | 119 +-----------------
 .../ActionLoopGo13ContainerTests.scala             |  22 ++--
 .../ActionLoopGo15ContainerTests.scala             |  22 ++--
 .../ActionLoopGoContainerTests.scala               |  11 +-
 tools/travis/publish.sh                            |   6 +-
 64 files changed, 744 insertions(+), 1031 deletions(-)

diff --git a/.gitignore b/.gitignore
index 6862d66..80e637f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 .gogradle/
 *.log
 tests/build/
+test.out
 
 # Dependencies
 vendor/
@@ -55,4 +56,3 @@ exec
 *_launcher_.go
 test.json
 pkg/
-bin/
diff --git a/.travis.yml b/.travis.yml
index d51fdc7..26b0c0e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -45,7 +45,7 @@ deploy:
       repo: apache/openwhisk-runtime-go
   - provider: script
     skip_cleanup: true
-    script: "./tools/travis/publish.sh openwhisk 1.11 nightly && ./tools/travis/publish.sh openwhisk 1.12 nightly"
+    script: "./tools/travis/publish.sh openwhisk 1.13 nightly && ./tools/travis/publish.sh openwhisk 1.15 nightly"
     on:
       branch: master
       repo: apache/openwhisk-runtime-go
diff --git a/CHANGES.md b/CHANGES.md
index f41ba59..9ba63f1 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -17,6 +17,9 @@
 #
 -->
 # 1.16.0 (next release)
+- removed build for go1.11 and go1.12
+- updated examples
+- added go 1.13 and 1.14 with Go modules
 - upgraded to go 1.12.17
 - add 'apt-get upgrade' to the image build to get latest security fixes during each build, for the case the base images are not updated frequently
 - added OW_WAIT_FOR_ACK such at if true, the proxy waits for an acknowledgement from the action on startup
diff --git a/docs/ACTION.md b/docs/ACTION.md
index bb37606..1a1eaa7 100644
--- a/docs/ACTION.md
+++ b/docs/ACTION.md
@@ -22,7 +22,7 @@
 
 ## How to write Go Actions
 
-The `action-golang-v1.11` runtime can execute actions written in the Go programming language in OpenWhisk, either precompiled binary or compiling sources on the fly.
+The `action-golang-v1.14` runtime can execute actions written in the Go programming language in OpenWhisk, either precompiled binary or compiling sources on the fly.
 
 ### Entry Point
 
@@ -78,7 +78,6 @@ The `actionloop` runtime can execute  generic Linux executable in an efficient w
 The protocol can be specified informally as follows.
 
 - Send an acknowledgement after initialization when required. If the environment variable `__OW_WAIT_FOR_ACK` is not empty, write on file descriptor 3 the string `{ "ok": true }`.
-
 - Read one line from standard input (file descriptor 0).
 - Parse the line as a JSON object. Currently the object will be in currently in the format:
 
@@ -128,7 +127,7 @@ done
 
 Note here we are just interested in the payload, but in general you may also want to retrieve other fields.
 
-Note the `actionloop` image will accept any source and will try to run it (if it is possible), while the `action-golang-v1.11`  will instead try to compile the sources assuming it is Golang instead.
+Note the `actionloop` image will accept any source and will try to run it (if it is possible), while the `action-golang-v1.15`  will instead try to compile the sources assuming it is Golang instead.
 
 <a name="actionloopgo">
 
@@ -146,4 +145,4 @@ If you send a zip file, you have to provide your implementation in a file called
 
 If you provide your own `main.main()`, the default `main` will not be generated.
 
-An example named `golang-main-standalone` is provided.
+An example named `standalone` is provided.
diff --git a/docs/BUILD.md b/docs/BUILD.md
index d268425..a97e4ce 100644
--- a/docs/BUILD.md
+++ b/docs/BUILD.md
@@ -43,10 +43,12 @@ To build the docker images, after compiling go proxy:
 
 This will build the images:
 
-* `action-golang-v1.11`: an image supporting  Go sources
-* `actionloop`: the base image, supporting generic executables ans shell script
+* `action-golang-v1.13`: an image supporting Go 1.13 sources (does expect an ack)
+* `action-golang-v1.14`: an image supporting Go 1.14 sources (does expect an ack)
+* `action-golang-v1.15`: an image supporting Go 1.15 sources (does expect an ack)
+* `actionloop-base`: the base image, supporting generic executables ans shell script (does not expect an ack)
 
-The `actionloop` image can be used for supporting other compiled programming languages as long as they implement a `compile` script and the *action loop* protocol described below.
+The `actionloop-base` image can be used for supporting other compiled programming languages as long as they implement a `compile` script and the *action loop* protocol described below. Please check [this documens](ENVVARS.md) for configuration options
 
 To run tests:
 
@@ -59,7 +61,7 @@ To run tests:
 
 If you want to develop the proxy and run tests natively, you can do it on Linux or OSX. Development has been tested on Ubuntu Linux (14.04) and OSX 10.13. Probably other distributions work, maybe even Windows with WSL, but since it is not tested YMMMV.
 
-You need to install, of course [go 1.11.0](https://golang.org/doc/install)
+You need to install, of course [go 1.14.x](https://golang.org/doc/install)
 
 Then you need a set of utilities used in tests:
 
diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md
index 9d9b696..c37f019 100644
--- a/docs/DEPLOY.md
+++ b/docs/DEPLOY.md
@@ -19,20 +19,20 @@
 
 # Deployment options
 
-There are two images provided: the `actionloop` and the `action-golang-v1.11` available. Each image accept different input in the deployment.
+There are a few images provided: the `actionloop-base` and the `action-golang-v1.13`, `action-golang-v1.14`, `action-golang-v1.15` available. Each image accept different input in the deployment.
 
 <a name="actionloop">
 
 ## Actionloop runtime
 
-The runtime `actionlooop` accepts:
+The runtime `actionlooop-base` accepts:
 
 - single file executable
 - a zip file containing an executables
 
 If the input is a single file, it can be either a in ELF format for architecture AMD64 implementing the ActionLoop protocol.
 
-It can also be a script, identified by the `#!` hash-bang path at the beginning. The default `actionloop` can execute `bash` shell scripts and can use the `jq` command to parse JSON files and the `curl` command to invoke other actions.
+It can also be a script, identified by the `#!` hash-bang path at the beginning. The default `actionloop-base` can execute `bash` shell scripts and can use the `jq` command to parse JSON files and the `curl` command to invoke other actions.
 
 If the file is a zipped file, it must contain in the top level (*not* in a subdirectory) an file named `exec`. This file must be in the same format as a single binary, either a binary or a script.
 
@@ -40,16 +40,16 @@ If the file is a zipped file, it must contain in the top level (*not* in a subdi
 
 ## Golang runtime
 
-The runtime `action-golang-v1.11` accepts:
+The runtime `action-golang-v1.15` (and past everions) accepts:
 
-- executable binaries implementing the ActionLoop protocol as Linux ELF executable compiled for the AMD64 architecture (as the `actionloop` runtme)
+- executable binaries implementing the ActionLoop protocol as Linux ELF executable compiled for the AMD64 architecture (as the `actionloop-base` runtme)
 - zip files containing a binary executable named `exec` in the top level, and it must be again a Linux ELF executable compiled for the AMD64 architecture
 - a single file action that is not an executable binary will be interpreted as source code and it will be compiled in a binary as described in the document about [actions](ACTION.md)
 - a zip file not containing in the top level a binary file `exec` will  be interpreted as a collection of zip files, and it will be compiled in a binary as described in the document about [actions](ACTION.md)
 
 Please note in the separate the rules about the name of the main function (that defaults to `main.Main`), and the rules about how to overwrite the `main.main`.
 
-## Using packages and vendor folder
+## Using packages and modules
 
 When you deploy a zip file, you can:
 
@@ -57,91 +57,20 @@ When you deploy a zip file, you can:
 - have some functions placed in some packages, like `hello`
 - have some third party dependencies you want to include in your sources
 
-If all your functions are in the main package, just place all your sources in the top level of your zip file
+You can manage those dependencies using appropriate `go.mod` files using relative and absolute references.
 
-### Use a package folder
-
-If some functions belong to a package, like `hello/`, you need to be careful with the layout of your source. The layout supported is the following:
-
-```
-golang-main-package/
-├── Makefile
-└── src
-    ├── hello
-    │   ├── hello.go
-    │   └── hello_test.go
-    └── main.go
-```
-
-You need to use a `src` folder, place the sources that belongs to the main package in the `src` and place sources of your package in the `src/hello` folder.
-
-Then you should import it your subpackage with `import "hello"`.
-Note that this means if you want to compile locally you have to set your GOPATH to parent directory of your `src` packages. Check below for using [VcCode](#vscode) as an editor with this setup.
-
-When you send the image you will have to zip the content
-
-Check the example `golang-main-package` and the associated `Makefile` for an example including also how to deploy and precompile your sources.
-
-### Using vendor folders
-
-When you need to use third part libraries, the runtime does not download them from Internet. You have to provide them,  downloading and placing them using the `vendor` folder mechanism. We are going to show here how to use the vendor folder with the `dep` tool.
-
-*NOTE* the `vendor` folder does not work at the top level, you have to use a `src` folder and a package folder to have also the vendor folder.
-
-If you want for example use the library `github.com/sirupsen/logrus` to manage your logs (a widely used drop-in replacement for the standard `log` package), you have to include it in your source code *in a sub package*.
-
-For example consider you have in the file `src/hello/hello.go` the import:
-
-```go
-import "github.com/sirupsen/logrus"
-```
-
-To create a vendor folder, you need to
-
-- install the [dep](https://github.com/golang/dep) tool
-- cd to the `src/hello` folder (*not* the `src` folder)
-- run `GOPATH=$PWD/../.. dep init` the first time (it will create 2 manifest files `Gopkg.lock` and `Gopkg.toml`) or `dep ensure` if you already have the manifest files.
-
-The layout will be something like this:
+For example you can use a local package `hello` with:
 
 ```
-golang-hello-vendor
-├── Makefile
-└── src
-    ├── hello
-    │   ├── Gopkg.lock
-    │   ├── Gopkg.toml
-    │   ├── hello.go
-    │   ├── hello_test.go
-    │   └── vendor
-    │       ├── github.com/...
-    │       └── golang.org/...
-    └── hello.go
+replace hello => ./hello
 ```
 
-Check the example `golang-hello-vendor`.
-
-Note you do not need to store the `vendor` folder in the version control system as it can be regenerated (only the manifest files), but you need to include the entire vendor folder when you deploy the action.
-
-If you need to use vendor folder in the main package, you need to create a directory `main` and place all the source code that would normally go in the top level, in the `main` folder instead.  A vendor folder in the top level *does not work*.
-
-<a name="vscode">
-
-### Using VsCode
-
-If you are using [VsCode](https://code.visualstudio.com/) as your Go development environment with the [VsCode Go](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go) support, and you want to get rid of errors and have it working properly, you need to configure it to support the suggested:
-
-- you need to have a `src` folder in your source
-- you need either to open the `src` folder as the top level source or add it as a folder in the workspace (not just have it as a subfolder)
-- you need to enable the option `go.inferGopath`
-
-Using this option, the GOPATH will be set to the parent directory of your `src` folder and you will not have errors in your imports.
+Check the example: `package-main` and `module-main` and look for the format of the `go.mod` files.
 
 <a name="precompile"/>
-
 ## Precompiling Go Sources Offline
 
-Compiling sources on the image can take some time when the images is initialized. You can speed up precompiling the sources using the image `action-golang-v1.11` as an offline compiler. You need `docker` for doing that.
+Compiling sources on the image can take some time when the images is initialized. You can speed up precompiling the sources using the image `action-golang-v1.15` as an offline compiler. You need `docker` for doing that.
 
 The images accepts a `-compile <main>` flag, and expects you provide sources in standard input. It will then compile them, emit the binary in standard output and errors in stderr. The output is always a zip file containing an executable.
 
@@ -149,20 +78,12 @@ If you have docker, you can do it this way:
 
 If you have a single source maybe in file `main.go`, with a function named `Main` just do this:
 
-`docker run openwhisk/action-golang-v1.11 -compile main <main.go >main.zip`
+`docker run openwhisk/action-golang-v1.15 -compile main <main.go >main.zip`
 
 If you have multiple sources in current directory, even with a subfolder with sources, you can compile it all with:
 
-`zip -r - * | docker run openwhisk/action-golang-v1.11 -compile main >main.zip`
-
-The  generated executable is suitable to be deployed in OpenWhisk using just the generic `actionloop` runtime.
-
-`wsk action create my/action main.zip -docker openwhisk/actionloop`
+`zip -r - * | docker run openwhisk/action-golang-v1.15 -compile main >main.zip`
 
-You can also use the full `action-golang-v1.11` as runtime, it is only bigger.
+You can then execute the code. Note you have to use the same runtime you used to build the image.
 
 Note that the output is always a zip file in  Linux AMD64 format so the executable can be run only inside a Docker Linux container.
-
-
-
-
diff --git a/examples/EXAMPLES.md b/examples/EXAMPLES.md
index 90a02e1..7705196 100644
--- a/examples/EXAMPLES.md
+++ b/examples/EXAMPLES.md
@@ -22,29 +22,24 @@
 This is a collection of examples.
 Tested on:
 
-- dep version 0.5.0 (check the version `dep version`)
-- Go version 1.11.1
+- Go version 1.14.6
 - GNU Make 3.81
-- Linux Ubuntu 14.04
-- Mac OSX 10.13
-- Windows, with Git Bash, Docker for Windows, make from ezwinports, zip.exe
+- Linux Ubuntu 18.04
+- Mac OSX 10.15.6
+- Windows 10 with WSL 2
 
 Each examples has a  Makefile with 4 targets:
 
 - `make deploy` (or just make) deploys the action, precompiling it
 - `make devel`  deploys the action in source format, leaving the compilation to the runtime
--  `make test` runs a simple test on the action; it should be already deployed
+- `make test` runs a simple test on the action; it should be already deployed
 - `clean` removes intermediate files
 
 Available examples:
 
-- [Simple Golang action](golang-main-single) main is `main.Main`
-- [Simple Golang action](golang-hello-single) main is `main.Hello`
-- [Golang action with a subpackage](golang-main-package) main is `main.Main` invoking a `hello.Hello`
-- [Golang action with a vendor folder](golang-main-vendor) main is `main.Main` using a dependency `github.com/rs/zerolog`
-- [Golang action with a subpackage and vendor folder](golang-hello-vendor) main is `main.Hello` invoking a `hello.Hello` using a dependency `github.com/sirupsen/logrus`
-- [Standalone Golang Action](golang-main-standalone) main is `main.main`, implements the ActionLoop directly
-- [Simple Bash action](bash-hello) a simple bash script action implementing the ActionLoop directly
-
-
-
+- [Simple Golang action](single-main) main is `main.Main`
+- [Simple Golang action](single-hello) main is `main.Hello`
+- [Golang action with a package](package-main) main is `main.Main` invoking a `hello.Hello` and a test
+- [Golang action with a module](module-main) main is `main.Main` using a dependency `github.com/rs/zerolog`
+- [Standalone Golang Action](standalone) implements the ActionLoop directly in go
+- [Simple Bash action](bash) action implementing the ActionLoop directly
diff --git a/examples/Makefile b/examples/Makefile
index 8ab0da8..8f7cdfa 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -16,37 +16,41 @@
 #
 
 # prefix
-IMAGES?=openwhisk
+OW_USER?=openwhisk
 
-all: .PHONY
-
-.PHONY: bash-hello golang-hello-single golang-main-single golang-main-standalone golang-main-package golang-main-vendor golang-hello-vendor
-
-bash-hello:
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
-
-golang-main-single:
-	cd $@ && OW_USER=$(IMAGES) make clean devel test
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
-
-golang-hello-single:
-	cd $@ && OW_USER=$(IMAGES) make clean devel test
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
+test: .PHONY
+	cat */test.out | grep 'Hello' | sort >test.out
+	diff test.out test.expected
 
-golang-main-standalone:
-	cd $@ && OW_USER=$(IMAGES) make clean devel test
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
-
-golang-main-package:
-	cd $@ && OW_USER=$(IMAGES) make clean devel test
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
-
-golang-main-vendor:
-	cd $@ && OW_USER=$(IMAGES) make clean devel test
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
-
-golang-hello-vendor:
-	cd $@ && OW_USER=$(IMAGES) make clean devel test
-	cd $@ && OW_USER=$(IMAGES) make clean deploy test
+all: .PHONY
 
+.PHONY: bash
+bash:
+	cd $@ && OW_USER=$(OW_USER) make clean deploy test
+
+.PHONY: standalone
+standalone:
+	cd $@ && OW_USER=$(OW_USER) make clean devel test
+	cd $@ && OW_USER=$(OW_USER) make clean deploy test
+
+.PHONY: single-main
+single-main:
+	cd $@ && OW_USER=$(OW_USER) make clean devel test
+	cd $@ && OW_USER=$(OW_USER) make clean deploy test
+
+.PHONY: single-hello
+single-hello:
+	cd $@ && OW_USER=$(OW_USER) make clean devel test
+	cd $@ && OW_USER=$(OW_USER) make clean deploy test
+
+.PHONY: package-main
+package-main:
+	cd $@ && OW_USER=$(OW_USER) make clean devel test
+	cd $@ && OW_USER=$(OW_USER) make clean deploy test
+
+.PHONY: module-main
+module-main:
+	# this exceeds 3 seconds for initializiation
+	#cd $@ && OW_USER=$(OW_USER) make clean devel test
+	cd $@ && OW_USER=$(OW_USER) make clean deploy test
 
diff --git a/examples/bash-hello/Makefile b/examples/bash/Makefile
similarity index 85%
rename from examples/bash-hello/Makefile
rename to examples/bash/Makefile
index 91948ca..4389205 100644
--- a/examples/bash-hello/Makefile
+++ b/examples/bash/Makefile
@@ -14,11 +14,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
 WSK?=wsk
 OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-NAME=bash-hello
+OW_RUNTIME?=$(OW_USER)/actionloop-base:nightly
+NAME=bash
 PACKAGE=test
 SRC=hello.sh
 
@@ -28,12 +27,13 @@ deploy: package.done
 devel: deploy
 
 test: test.json
-	$(WSK) action invoke $(PACKAGE)/$(NAME) -r
-	$(WSK) action invoke $(PACKAGE)/$(NAME) -P test.json -r
+	$(WSK) action invoke $(PACKAGE)/$(NAME) -r | tee -a test.out
+	$(WSK) action invoke $(PACKAGE)/$(NAME) -P test.json -r | tee -a test.out
 
 clean:
 	-$(WSK) action delete $(PACKAGE)/$(NAME)
 	-rm package.done test.json
+	-rm test.out
 
 package.done:
 	$(WSK) package update $(PACKAGE)
@@ -42,5 +42,4 @@ package.done:
 test.json:
 	echo '{ "name": "Mike" }' >test.json
 
-
 .PHONY: test devel deploy clean
diff --git a/examples/bash-hello/hello.sh b/examples/bash/hello.sh
similarity index 85%
rename from examples/bash-hello/hello.sh
rename to examples/bash/hello.sh
index 157eb69..1e87bf3 100755
--- a/examples/bash-hello/hello.sh
+++ b/examples/bash/hello.sh
@@ -15,10 +15,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+# NOTE by default actionloop classic does not use an ack
+# if enabled with OW_REQUIRES_ACK you need
+# echo '{"ok": true}'
 while read line
 do
    name="$(echo $line | jq -r .value.name)"
    test "$name" == "null" && name="world"
    echo msg="hello $name"
-   echo '{"bash": "'$name'"}' >&3
+   echo '{"bash": "Hello, '$name'"}' >&3
 done
diff --git a/examples/benchmark/init.sh b/examples/benchmark/init.sh
deleted file mode 100644
index d34951f..0000000
--- a/examples/benchmark/init.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/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.
-#
-INIT=${1:?action}
-jq -n --rawfile file $INIT '{ "value": {"main":"main", "code":$file}}' >$INIT.json
-curl -XPOST -H "Content-Type: application/json" http://localhost:8080/init -d @$INIT.json
diff --git a/examples/golang-hello-vendor/Makefile b/examples/golang-hello-vendor/Makefile
deleted file mode 100644
index 4f7ea0d..0000000
--- a/examples/golang-hello-vendor/Makefile
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-OW_COMPILER?=$(OW_USER)/action-golang-v1.11
-WSK?=wsk
-MAIN=hello
-PACKAGE=test
-SRCS=src/$(MAIN).go src/$(MAIN)/$(MAIN).go
-VENDORS=src/$(MAIN)/vendor
-NAME=golang-$(MAIN)-vendor
-BINZIP=$(MAIN)-bin.zip
-SRCZIP=$(MAIN)-src.zip
-
-deploy: package.done $(BINZIP)
-	$(WSK) action update $(PACKAGE)/$(NAME) $(BINZIP) --main $(MAIN) --docker $(OW_RUNTIME)
-
-devel: package.done $(SRCZIP)
-	$(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER)
-
-src/%/vendor:
-	cd $(@D) ; DEPPROJECTROOT=$(realpath $(@D)/../..) dep ensure
-
-$(BINZIP): $(SRCS) $(VENDORS) $(SRCZIP)
-	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRCZIP) >$(BINZIP)
-
-$(SRCZIP): $(SRCS) $(VENDORS)
-	cd src ; zip ../$(SRCZIP) -qr *
-
-clean:
-	-$(WSK) action delete $(PACKAGE)/$(NAME)
-	-rm $(BINZIP) $(SRCZIP) package.done test.json 2>/dev/null
-
-clean_vendor:
-	-rm -r $(VENDORS)
-
-test: test.json
-	$(WSK) action invoke test/$(NAME) -r
-	$(WSK) action invoke test/$(NAME) -P test.json -r
-
-test.json:
-	echo '{ "name": "Mike" }' >test.json
-
-package.done:
-	$(WSK) package update $(PACKAGE)
-	touch package.done
-
-.PHONY: deploy devel test clean
diff --git a/examples/golang-hello-vendor/src/hello/Gopkg.lock b/examples/golang-hello-vendor/src/hello/Gopkg.lock
deleted file mode 100644
index e516dc9..0000000
--- a/examples/golang-hello-vendor/src/hello/Gopkg.lock
+++ /dev/null
@@ -1,44 +0,0 @@
-# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
-
-
-[[projects]]
-  digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
-  name = "github.com/konsorten/go-windows-terminal-sequences"
-  packages = ["."]
-  pruneopts = "UT"
-  revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
-  version = "v1.0.1"
-
-[[projects]]
-  digest = "1:3f53e9e4dfbb664cd62940c9c4b65a2171c66acd0b7621a1a6b8e78513525a52"
-  name = "github.com/sirupsen/logrus"
-  packages = ["."]
-  pruneopts = "UT"
-  revision = "ad15b42461921f1fb3529b058c6786c6a45d5162"
-  version = "v1.1.1"
-
-[[projects]]
-  branch = "master"
-  digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8"
-  name = "golang.org/x/crypto"
-  packages = ["ssh/terminal"]
-  pruneopts = "UT"
-  revision = "a92615f3c49003920a58dedcf32cf55022cefb8d"
-
-[[projects]]
-  branch = "master"
-  digest = "1:f5aa274a0377f85735edc7fedfb0811d3cbc20af91633797cb359e29c3272271"
-  name = "golang.org/x/sys"
-  packages = [
-    "unix",
-    "windows",
-  ]
-  pruneopts = "UT"
-  revision = "fa43e7bc11baaae89f3f902b2b4d832b68234844"
-
-[solve-meta]
-  analyzer-name = "dep"
-  analyzer-version = 1
-  input-imports = ["github.com/sirupsen/logrus"]
-  solver-name = "gps-cdcl"
-  solver-version = 1
diff --git a/examples/golang-hello-vendor/src/hello/Gopkg.toml b/examples/golang-hello-vendor/src/hello/Gopkg.toml
deleted file mode 100644
index 4dad4be..0000000
--- a/examples/golang-hello-vendor/src/hello/Gopkg.toml
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Gopkg.toml example
-#
-# 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.
-#
-# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
-# for detailed Gopkg.toml documentation.
-#
-# required = ["github.com/user/thing/cmd/thing"]
-# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
-#
-# [[constraint]]
-#   name = "github.com/user/project"
-#   version = "1.0.0"
-#
-# [[constraint]]
-#   name = "github.com/user/project2"
-#   branch = "dev"
-#   source = "github.com/myfork/project2"
-#
-# [[override]]
-#   name = "github.com/x/y"
-#   version = "2.4.0"
-#
-# [prune]
-#   non-go = false
-#   go-tests = true
-#   unused-packages = true
-
-
-[[constraint]]
-  name = "github.com/sirupsen/logrus"
-  version = "1.1.1"
-
-[prune]
-  go-tests = true
-  unused-packages = true
diff --git a/examples/golang-hello-vendor/src/hello/hello.go b/examples/golang-hello-vendor/src/hello/hello.go
deleted file mode 100644
index d281621..0000000
--- a/examples/golang-hello-vendor/src/hello/hello.go
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package hello
-
-import (
-	"os"
-
-	"github.com/sirupsen/logrus"
-)
-
-var log = logrus.New()
-
-// Hello receive an event in format
-// { "name": "Mike"}
-// and returns a greeting in format
-// { "greetings": "Hello, Mike"}
-func Hello(args map[string]interface{}) map[string]interface{} {
-	log.Out = os.Stdout
-	res := make(map[string]interface{})
-	greetings := "world"
-	name, ok := args["name"].(string)
-	if ok {
-		greetings = name
-	}
-	res["golang-hello-vendor"] = "Hello, " + greetings
-	log.WithFields(logrus.Fields{"greetings": greetings}).Info("Hello")
-	return res
-}
diff --git a/examples/golang-hello-vendor/src/hello/hello_test.go b/examples/golang-hello-vendor/src/hello/hello_test.go
deleted file mode 100644
index 354e32a..0000000
--- a/examples/golang-hello-vendor/src/hello/hello_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package hello
-
-import (
-	"encoding/json"
-	"testing"
-)
-
-func TestHello(t *testing.T) {
-	var input = make(map[string]interface{})
-	input["name"] = "Mike"
-	output := Hello(input)
-	json, _ := json.Marshal(output)
-	if string(json) != `{"golang-hello-vendor":"Hello, Mike"}` {
-		t.Fail()
-	}
-}
-
-func TestHello_noName(t *testing.T) {
-	var input = make(map[string]interface{})
-	output := Hello(input)
-	json, _ := json.Marshal(output)
-	if string(json) != `{"golang-hello-vendor":"Hello, world"}` {
-		t.Fail()
-	}
-}
diff --git a/examples/golang-main-single/main.go b/examples/golang-main-single/main.go
deleted file mode 100644
index 5fdaf5d..0000000
--- a/examples/golang-main-single/main.go
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package main
-
-import "fmt"
-
-// Main function for the action
-func Main(obj map[string]interface{}) map[string]interface{} {
-	name, ok := obj["name"].(string)
-	if !ok {
-		name = "world"
-	}
-	fmt.Printf("name=%s\n", name)
-	msg := make(map[string]interface{})
-	msg["golang-main-single"] = "Hello, " + name + "!"
-	return msg
-}
diff --git a/examples/golang-main-vendor/src/main/Gopkg.lock b/examples/golang-main-vendor/src/main/Gopkg.lock
deleted file mode 100644
index 4e31c6b..0000000
--- a/examples/golang-main-vendor/src/main/Gopkg.lock
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
-
-
-[[projects]]
-  digest = "1:6342a41a66687c0d0eb1f4d946447bfb808c5136adeb92903ed07972071e19ac"
-  name = "github.com/rs/zerolog"
-  packages = [
-    ".",
-    "internal/cbor",
-    "internal/json",
-    "log",
-  ]
-  pruneopts = "UT"
-  revision = "338f9bc14084d22cb8eeacd6492861f8449d715c"
-  version = "v1.9.1"
-
-[solve-meta]
-  analyzer-name = "dep"
-  analyzer-version = 1
-  input-imports = [
-    "github.com/rs/zerolog",
-    "github.com/rs/zerolog/log",
-  ]
-  solver-name = "gps-cdcl"
-  solver-version = 1
diff --git a/examples/golang-main-vendor/src/main/Gopkg.toml b/examples/golang-main-vendor/src/main/Gopkg.toml
deleted file mode 100644
index c3dfb0e..0000000
--- a/examples/golang-main-vendor/src/main/Gopkg.toml
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Gopkg.toml example
-#
-# 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.
-#
-# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
-# for detailed Gopkg.toml documentation.
-#
-# required = ["github.com/user/thing/cmd/thing"]
-# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
-#
-# [[constraint]]
-#   name = "github.com/user/project"
-#   version = "1.0.0"
-#
-# [[constraint]]
-#   name = "github.com/user/project2"
-#   branch = "dev"
-#   source = "github.com/myfork/project2"
-#
-# [[override]]
-#   name = "github.com/x/y"
-#   version = "2.4.0"
-#
-# [prune]
-#   non-go = false
-#   go-tests = true
-#   unused-packages = true
-
-
-[[constraint]]
-  name = "github.com/rs/zerolog"
-  version = "1.9.1"
-
-[prune]
-  go-tests = true
-  unused-packages = true
diff --git a/examples/golang-main-vendor/Makefile b/examples/module-main/Makefile
similarity index 77%
rename from examples/golang-main-vendor/Makefile
rename to examples/module-main/Makefile
index efebea6..4ae74ba 100644
--- a/examples/golang-main-vendor/Makefile
+++ b/examples/module-main/Makefile
@@ -16,14 +16,13 @@
 #
 
 OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-OW_COMPILER?=$(OW_USER)/action-golang-v1.11
+OW_RUNTIME?=$(OW_USER)/action-golang-v1.15:nightly
+OW_COMPILER?=$(OW_USER)/action-golang-v1.15:nightly
 WSK?=wsk
 MAIN=main
 PACKAGE=test
-SRCS=src/$(MAIN)/$(MAIN).go
-VENDORS=src/$(MAIN)/vendor
-NAME=golang-$(MAIN)-vendor
+SRCS=main.go go.mod go.sum
+NAME=module-main
 BINZIP=$(MAIN)-bin.zip
 SRCZIP=$(MAIN)-src.zip
 
@@ -33,25 +32,20 @@ deploy: package.done $(BINZIP)
 devel: package.done $(SRCZIP)
 	$(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER)
 
-src/%/vendor:
-	cd $(@D) ; DEPPROJECTROOT=$(realpath $(@D)/../..) dep ensure
-
 $(BINZIP): $(SRCS) $(VENDORS) $(SRCZIP)
 	docker run -i $(OW_COMPILER) -compile $(MAIN) <$(SRCZIP) >$(BINZIP)
 
-$(SRCZIP): $(SRCS) $(VENDORS)
-	cd src ; zip ../$(SRCZIP) -qr *
+$(SRCZIP): $(SRCS)
+	zip $@ -qr $^
 
 clean:
 	-$(WSK) action delete $(PACKAGE)/$(NAME)
 	-rm $(BINZIP) $(SRCZIP) package.done test.json
-
-clean_vendor:
-	-rm -r $(VENDORS)
+	-rm test.out
 
 test: test.json
-	$(WSK) action invoke test/$(NAME) -r
-	$(WSK) action invoke test/$(NAME) -P test.json -r
+	$(WSK) action invoke test/$(NAME) -r | tee -a test.out
+	$(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out
 
 test.json:
 	echo '{ "name": "Mike" }' >test.json
diff --git a/examples/module-main/go.mod b/examples/module-main/go.mod
new file mode 100644
index 0000000..06556c2
--- /dev/null
+++ b/examples/module-main/go.mod
@@ -0,0 +1,5 @@
+module action
+
+go 1.14
+
+require github.com/rs/zerolog v1.19.0
diff --git a/examples/module-main/go.sum b/examples/module-main/go.sum
new file mode 100644
index 0000000..ee4ce07
--- /dev/null
+++ b/examples/module-main/go.sum
@@ -0,0 +1,12 @@
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg=
+github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/examples/golang-main-vendor/src/main/main.go b/examples/module-main/main.go
similarity index 95%
copy from examples/golang-main-vendor/src/main/main.go
copy to examples/module-main/main.go
index b687858..5a906df 100644
--- a/examples/golang-main-vendor/src/main/main.go
+++ b/examples/module-main/main.go
@@ -33,6 +33,6 @@ func Main(obj map[string]interface{}) map[string]interface{} {
 	}
 	log.Debug().Str("name", name).Msg("Hello")
 	msg := make(map[string]interface{})
-	msg["golang-main-vendor"] = "Hello, " + name + "!"
+	msg["module-main"] = "Hello, " + name + "!"
 	return msg
 }
diff --git a/examples/golang-main-package/Makefile b/examples/package-main/Makefile
similarity index 78%
rename from examples/golang-main-package/Makefile
rename to examples/package-main/Makefile
index 2c7cd55..6050065 100644
--- a/examples/golang-main-package/Makefile
+++ b/examples/package-main/Makefile
@@ -16,13 +16,13 @@
 #
 
 OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-OW_COMPILER?=$(OW_USER)/action-golang-v1.11
+OW_RUNTIME?=$(OW_USER)/action-golang-v1.15:nightly
+OW_COMPILER?=$(OW_USER)/action-golang-v1.15:nightly
 WSK?=wsk
 MAIN=main
 PACKAGE=test
-SRCS=src/$(MAIN).go src/hello/hello.go
-NAME=golang-$(MAIN)-package
+SRCS=$(MAIN).go go.mod hello/hello.go hello/go.mod
+NAME=package-main
 BINZIP=$(MAIN)-bin.zip
 SRCZIP=$(MAIN)-src.zip
 
@@ -33,18 +33,19 @@ devel: package.done $(SRCZIP)
 	$(WSK) action update $(PACKAGE)/$(NAME) $(SRCZIP) --main $(MAIN) --docker $(OW_COMPILER)
 
 $(BINZIP): $(SRCS)
-	cd src ; zip - -qr * | docker run -i $(OW_COMPILER) -compile $(MAIN) >../$(BINZIP)
+	zip - -qr $(SRCS) | docker run -i $(OW_COMPILER) -compile $(MAIN) >$(BINZIP)
 
 $(SRCZIP): $(SRCS)
-	cd src ; zip ../$(SRCZIP) -qr *
+	zip $@ -r $^
 
 clean:
 	-$(WSK) action delete $(PACKAGE)/$(NAME)
 	-rm $(BINZIP) $(SRCZIP) package.done test.json 2>/dev/null
+	-rm test.out
 
 test: test.json
-	$(WSK) action invoke test/$(NAME) -r
-	$(WSK) action invoke test/$(NAME) -P test.json -r
+	$(WSK) action invoke test/$(NAME) -r | tee -a test.out
+	$(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out
 
 test.json:
 	echo '{ "name": "Mike" }' >test.json
diff --git a/examples/package-main/go.mod b/examples/package-main/go.mod
new file mode 100644
index 0000000..3f25a14
--- /dev/null
+++ b/examples/package-main/go.mod
@@ -0,0 +1,7 @@
+module action
+
+go 1.14
+
+replace hello => ./hello
+
+require hello v0.0.0-00010101000000-000000000000
diff --git a/examples/package-main/hello/go.mod b/examples/package-main/hello/go.mod
new file mode 100644
index 0000000..f447636
--- /dev/null
+++ b/examples/package-main/hello/go.mod
@@ -0,0 +1,3 @@
+module hello
+
+go 1.14
diff --git a/examples/golang-main-package/src/hello/hello.go b/examples/package-main/hello/hello.go
similarity index 95%
rename from examples/golang-main-package/src/hello/hello.go
rename to examples/package-main/hello/hello.go
index da64077..140819a 100644
--- a/examples/golang-main-package/src/hello/hello.go
+++ b/examples/package-main/hello/hello.go
@@ -32,7 +32,7 @@ func Hello(args map[string]interface{}) map[string]interface{} {
 	if ok {
 		greetings = name
 	}
-	res["golang-main-package"] = "Hello, " + greetings
+	res["package-main"] = "Hello, " + greetings
 	fmt.Printf("Hello, %s\n", greetings)
 	return res
 }
diff --git a/examples/golang-main-package/src/hello/hello_test.go b/examples/package-main/hello/hello_test.go
similarity index 96%
rename from examples/golang-main-package/src/hello/hello_test.go
rename to examples/package-main/hello/hello_test.go
index fe6e15b..a824345 100644
--- a/examples/golang-main-package/src/hello/hello_test.go
+++ b/examples/package-main/hello/hello_test.go
@@ -29,7 +29,7 @@ func ExampleHello() {
 	fmt.Printf("%s", json)
 	// Output:
 	// Hello, Mike
-	// {"golang-main-package":"Hello, Mike"}
+	// {"package-main":"Hello, Mike"}
 }
 
 func ExampleHello_noName() {
diff --git a/examples/golang-main-package/src/main.go b/examples/package-main/main.go
similarity index 100%
copy from examples/golang-main-package/src/main.go
copy to examples/package-main/main.go
diff --git a/examples/golang-hello-single/Makefile b/examples/single-hello/Makefile
similarity index 84%
rename from examples/golang-hello-single/Makefile
rename to examples/single-hello/Makefile
index 9683f95..71817d7 100644
--- a/examples/golang-hello-single/Makefile
+++ b/examples/single-hello/Makefile
@@ -16,13 +16,13 @@
 #
 
 OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-OW_COMPILER?=$(OW_USER)/action-golang-v1.11
+OW_RUNTIME?=$(OW_USER)/action-golang-v1.15:nightly
+OW_COMPILER?=$(OW_USER)/action-golang-v1.15:nightly
 WSK?=wsk
 MAIN=hello
 PACKAGE=test
 SRC=$(MAIN).go
-NAME=golang-$(MAIN)-single
+NAME=single-hello
 ZIP=$(MAIN).zip
 
 deploy: package.done $(ZIP)
@@ -37,10 +37,11 @@ $(ZIP): $(SRC)
 clean:
 	-$(WSK) action delete $(PACKAGE)/$(NAME)
 	-rm $(ZIP) package.done test.json 2>/dev/null
+	-rm test.out
 
 test: test.json
-	$(WSK) action invoke test/$(NAME) -r
-	$(WSK) action invoke test/$(NAME) -P test.json -r
+	$(WSK) action invoke test/$(NAME) -r | tee -a test.out
+	$(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out
 
 test.json:
 	echo '{ "name": "Mike" }' >test.json
diff --git a/examples/golang-hello-single/hello.go b/examples/single-hello/hello.go
similarity index 95%
rename from examples/golang-hello-single/hello.go
rename to examples/single-hello/hello.go
index c2e3db7..68a25bc 100644
--- a/examples/golang-hello-single/hello.go
+++ b/examples/single-hello/hello.go
@@ -26,6 +26,6 @@ func Hello(obj map[string]interface{}) map[string]interface{} {
 	}
 	fmt.Printf("name=%s\n", name)
 	msg := make(map[string]interface{})
-	msg["golang-hello-single"] = "Hello, " + name + "!"
+	msg["single-hello"] = "Hello, " + name + "!"
 	return msg
 }
diff --git a/examples/golang-main-single/Makefile b/examples/single-main/Makefile
similarity index 84%
rename from examples/golang-main-single/Makefile
rename to examples/single-main/Makefile
index ff5c4ce..9cdd3b5 100644
--- a/examples/golang-main-single/Makefile
+++ b/examples/single-main/Makefile
@@ -16,13 +16,13 @@
 #
 
 OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-OW_COMPILER?=$(OW_USER)/action-golang-v1.11
+OW_RUNTIME?=$(OW_USER)/action-golang-v1.15:nightly
+OW_COMPILER?=$(OW_USER)/action-golang-v1.15:nightly
 WSK?=wsk
 MAIN=main
 PACKAGE=test
 SRC=$(MAIN).go
-NAME=golang-$(MAIN)-single
+NAME=single-main
 ZIP=$(MAIN).zip
 
 deploy: package.done $(ZIP)
@@ -37,10 +37,11 @@ $(ZIP): $(SRC)
 clean:
 	-$(WSK) action delete $(PACKAGE)/$(NAME)
 	-rm $(ZIP) package.done test.json 2>/dev/null
+	-rm test.out
 
 test: test.json
-	$(WSK) action invoke test/$(NAME) -r
-	$(WSK) action invoke test/$(NAME) -P test.json -r
+	$(WSK) action invoke test/$(NAME) -r | tee -a test.out
+	$(WSK) action invoke test/$(NAME) -P test.json -r | tee -a test.out
 
 test.json:
 	echo '{ "name": "Mike" }' >test.json
diff --git a/examples/benchmark/main.go b/examples/single-main/main.go
similarity index 95%
rename from examples/benchmark/main.go
rename to examples/single-main/main.go
index 5fdaf5d..a1606c4 100644
--- a/examples/benchmark/main.go
+++ b/examples/single-main/main.go
@@ -26,6 +26,6 @@ func Main(obj map[string]interface{}) map[string]interface{} {
 	}
 	fmt.Printf("name=%s\n", name)
 	msg := make(map[string]interface{})
-	msg["golang-main-single"] = "Hello, " + name + "!"
+	msg["single-main"] = "Hello, " + name + "!"
 	return msg
 }
diff --git a/examples/golang-main-standalone/Makefile b/examples/standalone/Makefile
similarity index 91%
rename from examples/golang-main-standalone/Makefile
rename to examples/standalone/Makefile
index e02c87d..ca6bb99 100644
--- a/examples/golang-main-standalone/Makefile
+++ b/examples/standalone/Makefile
@@ -16,13 +16,13 @@
 #
 
 OW_USER?=openwhisk
-OW_RUNTIME?=$(OW_USER)/actionloop-base
-OW_COMPILER?=$(OW_USER)/action-golang-v1.11
+OW_RUNTIME?=$(OW_USER)/action-golang-v1.15:nightly
+OW_COMPILER?=$(OW_USER)/action-golang-v1.15:nightly
 WSK?=wsk
 MAIN=main
 PACKAGE=test
-SRC=src/exec
-NAME=golang-$(MAIN)-standalone
+SRC=exec.go
+NAME=standalone
 ZIP=$(MAIN).zip
 
 deploy: package.done $(ZIP)
@@ -37,6 +37,7 @@ $(ZIP): $(SRC)
 clean:
 	-$(WSK) action delete $(PACKAGE)/$(NAME)
 	-rm $(ZIP) package.done test.json
+	-rm test.out
 
 test: test.json
 	$(WSK) action invoke test/$(NAME) -r
diff --git a/examples/golang-main-standalone/src/exec b/examples/standalone/exec.go
similarity index 93%
copy from examples/golang-main-standalone/src/exec
copy to examples/standalone/exec.go
index d26b062..52dfafc 100644
--- a/examples/golang-main-standalone/src/exec
+++ b/examples/standalone/exec.go
@@ -56,6 +56,10 @@ func main() {
 	if debug {
 		log.Println("started")
 	}
+	// send ack
+	// note that it depends on the runtime,
+	// go 1.13+ requires an ack, past versions does not
+	fmt.Fprintf(out, `{ "ok": true}%s`, "\n")
 	for {
 		// read one line
 		inbuf, err := reader.ReadBytes('\n')
@@ -119,6 +123,6 @@ func Main(obj map[string]interface{}) map[string]interface{} {
 	}
 	fmt.Printf("name=%s\n", name)
 	msg := make(map[string]interface{})
-	msg["main-standalone"] = "Hello, " + name + "!"
+	msg["standalone"] = "Hello, " + name + "!"
 	return msg
 }
diff --git a/examples/test.expected b/examples/test.expected
new file mode 100644
index 0000000..7948110
--- /dev/null
+++ b/examples/test.expected
@@ -0,0 +1,10 @@
+    "bash": "Hello, Mike"
+    "bash": "Hello, world"
+    "module-main": "Hello, Mike!"
+    "module-main": "Hello, world!"
+    "package-main": "Hello, Mike"
+    "package-main": "Hello, world"
+    "single-hello": "Hello, Mike!"
+    "single-hello": "Hello, world!"
+    "single-main": "Hello, Mike!"
+    "single-main": "Hello, world!"
diff --git a/go.mod b/go.mod
index 44da655..a4a2c19 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,8 @@ module github.com/apache/openwhisk-runtime-go
 
 go 1.12
 
-require github.com/stretchr/testify v1.3.0
+require (
+	github.com/rs/zerolog v1.19.0
+	github.com/sirupsen/logrus v1.6.0
+	github.com/stretchr/testify v1.3.0
+)
diff --git a/go.sum b/go.sum
index 4347755..02edd7d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,27 @@
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.19.0 h1:hYz4ZVdUgjXTBUmrkrw55j1nHx68LfOKIQk5IYtyScg=
+github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
+github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/golang1.11/Dockerfile b/golang1.11/Dockerfile
index 96a81a6..1291c4e 100644
--- a/golang1.11/Dockerfile
+++ b/golang1.11/Dockerfile
@@ -15,14 +15,14 @@
 # limitations under the License.
 #
 FROM golang:1.11.13
-RUN echo "deb http://deb.debian.org/debian stretch-backports main contrib non-free" >>/etc/apt/sources.list \
+RUN echo "deb http://deb.debian.org/debian buster-backports main contrib non-free" >>/etc/apt/sources.list \
     && apt-get update \
     && apt-get -y --no-install-recommends upgrade \
     && apt-get -y --no-install-recommends install \
                         curl jq git \
-                        librdkafka1=0.11.6-1~bpo9+1 \
-                        librdkafka++1=0.11.6-1~bpo9+1 \
-                        librdkafka-dev=0.11.6-1~bpo9+1 \
+                        librdkafka1=0.11.6-1.1 \
+                        librdkafka++1=0.11.6-1.1 \
+                        librdkafka-dev=0.11.6-1.1 \
     && apt-get clean \
     && rm -rf /var/lib/apt/lists/* \
     && mkdir /action
diff --git a/golang1.12/Dockerfile b/golang1.12/Dockerfile
index 83ba09c..5713ef1 100644
--- a/golang1.12/Dockerfile
+++ b/golang1.12/Dockerfile
@@ -15,14 +15,14 @@
 # limitations under the License.
 #
 FROM golang:1.12.17
-RUN echo "deb http://deb.debian.org/debian stretch-backports main contrib non-free" >>/etc/apt/sources.list \
+RUN echo "deb http://deb.debian.org/debian buster-backports main contrib non-free" >>/etc/apt/sources.list \
     && apt-get update \
     && apt-get -y --no-install-recommends upgrade \
     && apt-get -y --no-install-recommends install \
                         curl jq git \
-                        librdkafka1=0.11.6-1~bpo9+1 \
-                        librdkafka++1=0.11.6-1~bpo9+1 \
-                        librdkafka-dev=0.11.6-1~bpo9+1 \
+                        librdkafka1=0.11.6-1.1 \
+                        librdkafka++1=0.11.6-1.1 \
+                        librdkafka-dev=0.11.6-1.1 \
     && apt-get clean \
     && rm -rf /var/lib/apt/lists/* \
     && mkdir /action
diff --git a/golang1.11/Dockerfile b/golang1.13/Dockerfile
similarity index 53%
copy from golang1.11/Dockerfile
copy to golang1.13/Dockerfile
index 96a81a6..816fe7a 100644
--- a/golang1.11/Dockerfile
+++ b/golang1.13/Dockerfile
@@ -14,22 +14,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-FROM golang:1.11.13
-RUN echo "deb http://deb.debian.org/debian stretch-backports main contrib non-free" >>/etc/apt/sources.list \
-    && apt-get update \
-    && apt-get -y --no-install-recommends upgrade \
-    && apt-get -y --no-install-recommends install \
-                        curl jq git \
-                        librdkafka1=0.11.6-1~bpo9+1 \
-                        librdkafka++1=0.11.6-1~bpo9+1 \
-                        librdkafka-dev=0.11.6-1~bpo9+1 \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && mkdir /action
-
+FROM golang:1.13.14
+RUN echo "deb http://deb.debian.org/debian buster-backports main contrib non-free" \
+     >>/etc/apt/sources.list &&\
+    echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections &&\
+    apt-get update && apt-get install -y apt-utils
+RUN apt-get install -y \
+     curl \
+     jq \
+     git \
+     vim &&\
+    apt-get -y install \
+     librdkafka1=0.11.6-1.1 \
+     librdkafka++1=0.11.6-1.1 && \
+    apt-get -y install \
+     librdkafka-dev=0.11.6-1.1 && \
+    rm -rf /var/lib/apt/lists/* && \
+    go get -u github.com/go-delve/delve/cmd/dlv
+RUN mkdir /action
 WORKDIR /action
 ADD proxy /bin/proxy
-ADD gobuild.py /bin/compile
-ADD gobuild.py.launcher.go /bin/compile.launcher.go
+ADD bin/compile /bin/compile
+ADD lib/launcher.go /lib/launcher.go
 ENV OW_COMPILER=/bin/compile
+ENV OW_LOG_INIT_ERROR=1
+ENV OW_WAIT_FOR_ACK=1
+ENV OW_EXECUTION_ENV=openwhisk/action-golang-v1.13
 ENTRYPOINT [ "/bin/proxy" ]
diff --git a/examples/benchmark/Makefile b/golang1.13/Makefile
similarity index 56%
rename from examples/benchmark/Makefile
rename to golang1.13/Makefile
index b3bf6f5..5f86e0a 100644
--- a/examples/benchmark/Makefile
+++ b/golang1.13/Makefile
@@ -14,27 +14,32 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+IMG=action-golang-v1.13:latest
 
-IMG?=whisk/action-golang-v1.11
-IMG2?=whisk/actionloop
+build:
+	../gradlew distDocker
 
-all: golang bash
+localbuild:
+	GOOS=linux GOARCH=amd64 go build -o proxy -a  -ldflags '-extldflags "-static"' ../main/proxy.go
+	docker build -t $(IMG) .
+	docker tag $(IMG) whisk/$(IMG)
 
-test.lua:
-	echo 'wrk.method = "POST"'>test.lua
-	echo "wrk.body = '{\"value\":{\"name\":\"Mike\"}}'">>test.lua
-	echo 'wrk.headers["Content-Type"] = "application/json"'>>test.lua
+push: build
+	docker tag $(IMG) actionloop/$(IMG)
+	docker push actionloop/$(IMG)
 
-golang: test.lua
-	docker run -d --name under-test --rm -p 8080:8080 $(IMG)
-	bash init.sh main.go
-	wrk -t1 -c1 -stest.lua http://localhost:8080/run
-	docker kill under-test
+clean:
+	docker rmi -f whisk/$(IMG) actionloop/$(IMG)
 
-bash: test.lua
-	docker run -d --name under-test --rm -p 8080:8080 $(IMG2)
-	bash init.sh main.sh
-	wrk -t1 -c1 -stest.lua http://localhost:8080/run
-	docker kill under-test
+.PHONY: debug
+debug:
+	docker run -p 8080:8080 -p 8079:8079 \
+	--name go-action --rm -ti --entrypoint=/bin/bash \
+	-e OW_COMPILER=/mnt/bin/compile \
+	-v $(PWD):/mnt whisk/$(IMG)
 
-.PHONY: all golang bash
+enter:
+enter:
+	docker exec -ti go-action bash
+
+.PHONY: build clean  debug
diff --git a/golang1.13/bin/compile b/golang1.13/bin/compile
new file mode 100755
index 0000000..9b1217f
--- /dev/null
+++ b/golang1.13/bin/compile
@@ -0,0 +1,138 @@
+#!/usr/bin/python -u
+"""Golang Action Compiler
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+from __future__ import print_function
+import os, os.path, sys, re, shutil, subprocess, traceback, codecs
+from os.path import dirname, exists
+from time import sleep
+
+# write a file creating intermediate directories
+def write_file(file, body, executable=False):
+    try: os.makedirs(dirname(file), mode=0o755)
+    except: pass
+    with open(file, mode="wb") as f:
+        f.write(body)
+    if executable:
+        os.chmod(file, 0o755)
+
+# copy a file eventually replacing a substring
+def copy_replace(src, dst, match=None, replacement=""):
+    with open(src, 'rb') as s:
+        body = s.read()
+        if match:
+            body = body.replace(match, replacement)
+        write_file(dst, body)
+
+
+def sources(launcher, source_dir, main):
+    func = main.capitalize()
+    has_main = None
+
+    # copy the exec to exec.go
+    # also check if it has a main in it
+    src = "%s/exec" % source_dir
+    dst = "%s/exec__.go" % source_dir
+    if os.path.isfile(src):
+        with codecs.open(src, 'r', 'utf-8') as s:
+            with codecs.open(dst, 'w', 'utf-8') as d:
+                body = s.read()
+                has_main = re.match(r".*package\s+main\W.*func\s+main\s*\(\s*\)", body, flags=re.DOTALL)
+                d.write(body)
+
+    # copy the launcher fixing the main
+    if not has_main:
+        dst = "%s/main__.go" % source_dir
+        if os.path.isdir("%s/main" % source_dir):
+            dst = "%s/main/main__.go" % source_dir
+        with codecs.open(dst, 'w', 'utf-8') as d:
+            with codecs.open(launcher, 'r', 'utf-8') as e:
+                code = e.read()
+                code = code.replace("Main", func)
+                d.write(code)
+
+def build(source_dir, target_dir):
+    # compile...
+    source_dir = os.path.abspath(source_dir)
+    parent = dirname(source_dir)
+    target = os.path.abspath("%s/exec" % target_dir)
+    if os.environ.get("__OW_EXECUTION_ENV"):
+      write_file("%s.env" % target, os.environ["__OW_EXECUTION_ENV"])
+
+    env = {
+      "GOROOT": "/usr/local/go",
+      "GOPATH": "/home/go",
+      "PATH": os.environ["PATH"],
+      "GOCACHE": "/tmp",
+      "GO111MODULE": "on"
+    }
+
+    gomod = "%s/go.mod" % source_dir
+    with open(os.devnull, "w") as dn:
+        if exists(gomod):
+            ret = subprocess.call(["go", "mod", "download"], cwd=source_dir, env=env, stderr=dn, stdout=dn)
+            if ret != 0:
+                print("cannot download modules")
+                return
+        else:
+            ret = subprocess.call(["go", "mod", "init", "exec"], cwd=source_dir, env=env, stdout=dn, stderr=dn)
+            if ret != 0:
+                print("cannot init modules")
+                return
+
+    ldflags = "-s -w"
+    gobuild = ["go", "build", "-o", target, "-ldflags", ldflags]
+    if os.environ.get("__OW_EXECUTION_ENV"):
+        ldflags += " -X main.OwExecutionEnv=%s" % os.environ["__OW_EXECUTION_ENV"]
+    ret = subprocess.call(gobuild, cwd=source_dir, env=env)
+    if ret != 0:
+        print("failed", " ".join(gobuild), "\nin", source_dir, "\nenv", env)
+
+def debug(source_dir, target_dir, port):
+    source_dir = os.path.abspath(source_dir)
+    target = os.path.abspath("%s/exec" % target_dir)
+    if os.environ.get("__OW_EXECUTION_ENV"):
+      write_file("%s/exec.env" % source_dir, os.environ["__OW_EXECUTION_ENV"])
+    shutil.rmtree(target_dir)
+    shutil.move(source_dir, target_dir)
+    write_file(target, """#!/bin/bash
+cd "$(dirname $0)"
+export GOCACHE=/tmp
+export PATH=%s
+exec script -q  -c '/go/bin/dlv debug --headless --listen=127.0.0.1:%s --continue --accept-multiclient --log-dest /tmp/delve.log'
+""" % (os.environ["PATH"], port) , True)   
+ 
+def main(argv):
+    if len(argv) < 4:
+        print("usage: <main-file> <source-dir> <target-dir>")
+        sys.exit(1)
+
+    main = argv[1]
+    source_dir = argv[2]
+    target_dir = argv[3]
+    launcher = dirname(dirname(argv[0]))+"/lib/launcher.go"
+    sources(launcher, source_dir, main)
+
+    # if the debug port is present and not empty build with debug
+    if os.environ.get("__OW_DEBUG_PORT"):
+        debug(source_dir, target_dir, os.environ["__OW_DEBUG_PORT"])
+    else:
+        build(source_dir, target_dir)
+
+if __name__ == '__main__':
+    main(sys.argv)
diff --git a/examples/golang-main-vendor/src/main/main.go b/golang1.13/build.gradle
similarity index 63%
copy from examples/golang-main-vendor/src/main/main.go
copy to golang1.13/build.gradle
index b687858..5323ec2 100644
--- a/examples/golang-main-vendor/src/main/main.go
+++ b/golang1.13/build.gradle
@@ -14,25 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package main
 
-import (
-	"github.com/rs/zerolog"
-	"github.com/rs/zerolog/log"
-)
+ext.dockerImageName = 'action-golang-v1.13'
+apply from: '../gradle/docker.gradle'
 
-func init() {
-	zerolog.TimeFieldFormat = ""
+distDocker.dependsOn 'staticBuildProxy'
+distDocker.finalizedBy('cleanup')
+
+task staticBuildProxy(type: Exec) {
+	environment CGO_ENABLED: "0"
+	environment GOOS: "linux"
+	environment GOARCH: "amd64"
+    environment GO111MODULE: "on"
+
+	commandLine 'go', 'build',
+		'-o',  'proxy', '-a',
+		'-ldflags', '-extldflags "-static"',
+		'../main/proxy.go'
 }
 
-// Main function for the action
-func Main(obj map[string]interface{}) map[string]interface{} {
-	name, ok := obj["name"].(string)
-	if !ok {
-		name = "world"
-	}
-	log.Debug().Str("name", name).Msg("Hello")
-	msg := make(map[string]interface{})
-	msg["golang-main-vendor"] = "Hello, " + name + "!"
-	return msg
+task cleanup(type: Delete) {
+    delete 'proxy'
 }
diff --git a/examples/golang-main-standalone/src/exec b/golang1.13/lib/launcher.go
similarity index 78%
copy from examples/golang-main-standalone/src/exec
copy to golang1.13/lib/launcher.go
index d26b062..f0d27e3 100644
--- a/examples/golang-main-standalone/src/exec
+++ b/golang1.13/lib/launcher.go
@@ -28,18 +28,26 @@ import (
 	"strings"
 )
 
+// OwExecutionEnv is the execution environment set at compile time
+var OwExecutionEnv = ""
+
 func main() {
+	// check if the execution enviroment is correct
+	if OwExecutionEnv != "" && OwExecutionEnv != os.Getenv("__OW_EXECUTION_ENV") {
+		fmt.Println("Execution Environment Mismatch")
+		fmt.Println("Expected: ", OwExecutionEnv)
+		fmt.Println("Actual: ", os.Getenv("__OW_EXECUTION_ENV"))
+		os.Exit(1)
+	}
+
 	// debugging
 	var debug = os.Getenv("OW_DEBUG") != ""
-
 	if debug {
-		filename := os.Getenv("OW_DEBUG")
-		f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
+		f, err := os.OpenFile("/tmp/action.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
 		if err == nil {
 			log.SetOutput(f)
-			defer f.Close()
 		}
-		log.Printf("ACTION ENV: %v", os.Environ())
+		log.Printf("Environment: %v", os.Environ())
 	}
 
 	// assign the main function
@@ -52,10 +60,13 @@ func main() {
 	defer out.Close()
 	reader := bufio.NewReader(os.Stdin)
 
-	// read-eval-print loop
+	// acknowledgement of started action
+	fmt.Fprintf(out, `{ "ok": true}%s`, "\n")
 	if debug {
-		log.Println("started")
+		log.Println("action started")
 	}
+
+	// read-eval-print loop
 	for {
 		// read one line
 		inbuf, err := reader.ReadBytes('\n')
@@ -80,7 +91,6 @@ func main() {
 			log.Printf("%v\n", input)
 		}
 		// set environment variables
-		err = json.Unmarshal(inbuf, &input)
 		for k, v := range input {
 			if k == "value" {
 				continue
@@ -105,20 +115,8 @@ func main() {
 		}
 		output = bytes.Replace(output, []byte("\n"), []byte(""), -1)
 		if debug {
-			log.Printf("'<<<%s'<<<", output)
+			log.Printf("<<<'%s'<<<", output)
 		}
 		fmt.Fprintf(out, "%s\n", output)
 	}
 }
-
-// Main function for the action
-func Main(obj map[string]interface{}) map[string]interface{} {
-	name, ok := obj["name"].(string)
-	if !ok {
-		name = "world"
-	}
-	fmt.Printf("name=%s\n", name)
-	msg := make(map[string]interface{})
-	msg["main-standalone"] = "Hello, " + name + "!"
-	return msg
-}
diff --git a/golang1.11/Dockerfile b/golang1.15/Dockerfile
similarity index 53%
copy from golang1.11/Dockerfile
copy to golang1.15/Dockerfile
index 96a81a6..1063513 100644
--- a/golang1.11/Dockerfile
+++ b/golang1.15/Dockerfile
@@ -14,22 +14,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-FROM golang:1.11.13
-RUN echo "deb http://deb.debian.org/debian stretch-backports main contrib non-free" >>/etc/apt/sources.list \
-    && apt-get update \
-    && apt-get -y --no-install-recommends upgrade \
-    && apt-get -y --no-install-recommends install \
-                        curl jq git \
-                        librdkafka1=0.11.6-1~bpo9+1 \
-                        librdkafka++1=0.11.6-1~bpo9+1 \
-                        librdkafka-dev=0.11.6-1~bpo9+1 \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* \
-    && mkdir /action
-
+FROM golang:1.15.0
+RUN echo "deb http://deb.debian.org/debian buster-backports main contrib non-free" \
+     >>/etc/apt/sources.list &&\
+    echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections &&\
+    apt-get update && apt-get install -y apt-utils
+RUN apt-get install -y \
+     curl \
+     jq \
+     git \
+     vim &&\
+    apt-get -y install \
+     librdkafka1=0.11.6-1.1 \
+     librdkafka++1=0.11.6-1.1 && \
+    apt-get -y install \
+     librdkafka-dev=0.11.6-1.1 && \
+    rm -rf /var/lib/apt/lists/* && \
+    go get -u github.com/go-delve/delve/cmd/dlv
+RUN mkdir /action
 WORKDIR /action
 ADD proxy /bin/proxy
-ADD gobuild.py /bin/compile
-ADD gobuild.py.launcher.go /bin/compile.launcher.go
+ADD bin/compile /bin/compile
+ADD lib/launcher.go /lib/launcher.go
 ENV OW_COMPILER=/bin/compile
+ENV OW_LOG_INIT_ERROR=1
+ENV OW_WAIT_FOR_ACK=1
+ENV OW_EXECUTION_ENV=openwhisk/action-golang-v1.15
 ENTRYPOINT [ "/bin/proxy" ]
diff --git a/examples/benchmark/main.sh b/golang1.15/Makefile
old mode 100755
new mode 100644
similarity index 56%
rename from examples/benchmark/main.sh
rename to golang1.15/Makefile
index d8ddb7f..989ed11
--- a/examples/benchmark/main.sh
+++ b/golang1.15/Makefile
@@ -1,4 +1,3 @@
-#!/bin/bash
 #
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
@@ -15,9 +14,31 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-while read line
-do
-   name="$(echo $line | jq -r .value.name)"
-   echo msg="hello $name"
-   echo '{"hello": "'$name'"}' >&3
-done
+IMG=action-golang-v1.15
+
+build:
+	../gradlew distDocker
+
+localbuild:
+	GOOS=linux GOARCH=amd64 go build -o proxy -a  -ldflags '-extldflags "-static"' ../main/proxy.go
+	docker build -t $(IMG) .
+	docker tag $(IMG) whisk/$(IMG)
+
+push: build
+	docker tag $(IMG) actionloop/$(IMG)
+	docker push actionloop/$(IMG):nightly
+
+clean:
+	docker rmi -f whisk/$(IMG) actionloop/$(IMG)
+
+debug: build
+	docker run -p 8080:8080 \
+	--name go-action --rm -ti --entrypoint=/bin/bash \
+	-e OW_COMPILER=/mnt/bin/compile \
+	-v $(PWD):/mnt whisk/$(IMG)
+
+enter:
+	docker exec -ti go-action bash
+
+
+.PHONY: build push clean debug enter
diff --git a/golang1.15/bin/compile b/golang1.15/bin/compile
new file mode 100755
index 0000000..9b1217f
--- /dev/null
+++ b/golang1.15/bin/compile
@@ -0,0 +1,138 @@
+#!/usr/bin/python -u
+"""Golang Action Compiler
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""
+from __future__ import print_function
+import os, os.path, sys, re, shutil, subprocess, traceback, codecs
+from os.path import dirname, exists
+from time import sleep
+
+# write a file creating intermediate directories
+def write_file(file, body, executable=False):
+    try: os.makedirs(dirname(file), mode=0o755)
+    except: pass
+    with open(file, mode="wb") as f:
+        f.write(body)
+    if executable:
+        os.chmod(file, 0o755)
+
+# copy a file eventually replacing a substring
+def copy_replace(src, dst, match=None, replacement=""):
+    with open(src, 'rb') as s:
+        body = s.read()
+        if match:
+            body = body.replace(match, replacement)
+        write_file(dst, body)
+
+
+def sources(launcher, source_dir, main):
+    func = main.capitalize()
+    has_main = None
+
+    # copy the exec to exec.go
+    # also check if it has a main in it
+    src = "%s/exec" % source_dir
+    dst = "%s/exec__.go" % source_dir
+    if os.path.isfile(src):
+        with codecs.open(src, 'r', 'utf-8') as s:
+            with codecs.open(dst, 'w', 'utf-8') as d:
+                body = s.read()
+                has_main = re.match(r".*package\s+main\W.*func\s+main\s*\(\s*\)", body, flags=re.DOTALL)
+                d.write(body)
+
+    # copy the launcher fixing the main
+    if not has_main:
+        dst = "%s/main__.go" % source_dir
+        if os.path.isdir("%s/main" % source_dir):
+            dst = "%s/main/main__.go" % source_dir
+        with codecs.open(dst, 'w', 'utf-8') as d:
+            with codecs.open(launcher, 'r', 'utf-8') as e:
+                code = e.read()
+                code = code.replace("Main", func)
+                d.write(code)
+
+def build(source_dir, target_dir):
+    # compile...
+    source_dir = os.path.abspath(source_dir)
+    parent = dirname(source_dir)
+    target = os.path.abspath("%s/exec" % target_dir)
+    if os.environ.get("__OW_EXECUTION_ENV"):
+      write_file("%s.env" % target, os.environ["__OW_EXECUTION_ENV"])
+
+    env = {
+      "GOROOT": "/usr/local/go",
+      "GOPATH": "/home/go",
+      "PATH": os.environ["PATH"],
+      "GOCACHE": "/tmp",
+      "GO111MODULE": "on"
+    }
+
+    gomod = "%s/go.mod" % source_dir
+    with open(os.devnull, "w") as dn:
+        if exists(gomod):
+            ret = subprocess.call(["go", "mod", "download"], cwd=source_dir, env=env, stderr=dn, stdout=dn)
+            if ret != 0:
+                print("cannot download modules")
+                return
+        else:
+            ret = subprocess.call(["go", "mod", "init", "exec"], cwd=source_dir, env=env, stdout=dn, stderr=dn)
+            if ret != 0:
+                print("cannot init modules")
+                return
+
+    ldflags = "-s -w"
+    gobuild = ["go", "build", "-o", target, "-ldflags", ldflags]
+    if os.environ.get("__OW_EXECUTION_ENV"):
+        ldflags += " -X main.OwExecutionEnv=%s" % os.environ["__OW_EXECUTION_ENV"]
+    ret = subprocess.call(gobuild, cwd=source_dir, env=env)
+    if ret != 0:
+        print("failed", " ".join(gobuild), "\nin", source_dir, "\nenv", env)
+
+def debug(source_dir, target_dir, port):
+    source_dir = os.path.abspath(source_dir)
+    target = os.path.abspath("%s/exec" % target_dir)
+    if os.environ.get("__OW_EXECUTION_ENV"):
+      write_file("%s/exec.env" % source_dir, os.environ["__OW_EXECUTION_ENV"])
+    shutil.rmtree(target_dir)
+    shutil.move(source_dir, target_dir)
+    write_file(target, """#!/bin/bash
+cd "$(dirname $0)"
+export GOCACHE=/tmp
+export PATH=%s
+exec script -q  -c '/go/bin/dlv debug --headless --listen=127.0.0.1:%s --continue --accept-multiclient --log-dest /tmp/delve.log'
+""" % (os.environ["PATH"], port) , True)   
+ 
+def main(argv):
+    if len(argv) < 4:
+        print("usage: <main-file> <source-dir> <target-dir>")
+        sys.exit(1)
+
+    main = argv[1]
+    source_dir = argv[2]
+    target_dir = argv[3]
+    launcher = dirname(dirname(argv[0]))+"/lib/launcher.go"
+    sources(launcher, source_dir, main)
+
+    # if the debug port is present and not empty build with debug
+    if os.environ.get("__OW_DEBUG_PORT"):
+        debug(source_dir, target_dir, os.environ["__OW_DEBUG_PORT"])
+    else:
+        build(source_dir, target_dir)
+
+if __name__ == '__main__':
+    main(sys.argv)
diff --git a/examples/golang-main-vendor/src/main/main.go b/golang1.15/build.gradle
similarity index 63%
rename from examples/golang-main-vendor/src/main/main.go
rename to golang1.15/build.gradle
index b687858..67da25b 100644
--- a/examples/golang-main-vendor/src/main/main.go
+++ b/golang1.15/build.gradle
@@ -14,25 +14,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package main
 
-import (
-	"github.com/rs/zerolog"
-	"github.com/rs/zerolog/log"
-)
+ext.dockerImageName = 'action-golang-v1.15'
+apply from: '../gradle/docker.gradle'
 
-func init() {
-	zerolog.TimeFieldFormat = ""
+distDocker.dependsOn 'staticBuildProxy'
+distDocker.finalizedBy('cleanup')
+
+task staticBuildProxy(type: Exec) {
+	environment CGO_ENABLED: "0"
+	environment GOOS: "linux"
+	environment GOARCH: "amd64"
+    environment GO111MODULE: "on"
+
+	commandLine 'go', 'build',
+		'-o',  'proxy', '-a',
+		'-ldflags', '-extldflags "-static"',
+		'../main/proxy.go'
 }
 
-// Main function for the action
-func Main(obj map[string]interface{}) map[string]interface{} {
-	name, ok := obj["name"].(string)
-	if !ok {
-		name = "world"
-	}
-	log.Debug().Str("name", name).Msg("Hello")
-	msg := make(map[string]interface{})
-	msg["golang-main-vendor"] = "Hello, " + name + "!"
-	return msg
+task cleanup(type: Delete) {
+    delete 'proxy'
 }
diff --git a/examples/golang-main-standalone/src/exec b/golang1.15/lib/launcher.go
similarity index 78%
rename from examples/golang-main-standalone/src/exec
rename to golang1.15/lib/launcher.go
index d26b062..f0d27e3 100644
--- a/examples/golang-main-standalone/src/exec
+++ b/golang1.15/lib/launcher.go
@@ -28,18 +28,26 @@ import (
 	"strings"
 )
 
+// OwExecutionEnv is the execution environment set at compile time
+var OwExecutionEnv = ""
+
 func main() {
+	// check if the execution enviroment is correct
+	if OwExecutionEnv != "" && OwExecutionEnv != os.Getenv("__OW_EXECUTION_ENV") {
+		fmt.Println("Execution Environment Mismatch")
+		fmt.Println("Expected: ", OwExecutionEnv)
+		fmt.Println("Actual: ", os.Getenv("__OW_EXECUTION_ENV"))
+		os.Exit(1)
+	}
+
 	// debugging
 	var debug = os.Getenv("OW_DEBUG") != ""
-
 	if debug {
-		filename := os.Getenv("OW_DEBUG")
-		f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
+		f, err := os.OpenFile("/tmp/action.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
 		if err == nil {
 			log.SetOutput(f)
-			defer f.Close()
 		}
-		log.Printf("ACTION ENV: %v", os.Environ())
+		log.Printf("Environment: %v", os.Environ())
 	}
 
 	// assign the main function
@@ -52,10 +60,13 @@ func main() {
 	defer out.Close()
 	reader := bufio.NewReader(os.Stdin)
 
-	// read-eval-print loop
+	// acknowledgement of started action
+	fmt.Fprintf(out, `{ "ok": true}%s`, "\n")
 	if debug {
-		log.Println("started")
+		log.Println("action started")
 	}
+
+	// read-eval-print loop
 	for {
 		// read one line
 		inbuf, err := reader.ReadBytes('\n')
@@ -80,7 +91,6 @@ func main() {
 			log.Printf("%v\n", input)
 		}
 		// set environment variables
-		err = json.Unmarshal(inbuf, &input)
 		for k, v := range input {
 			if k == "value" {
 				continue
@@ -105,20 +115,8 @@ func main() {
 		}
 		output = bytes.Replace(output, []byte("\n"), []byte(""), -1)
 		if debug {
-			log.Printf("'<<<%s'<<<", output)
+			log.Printf("<<<'%s'<<<", output)
 		}
 		fmt.Fprintf(out, "%s\n", output)
 	}
 }
-
-// Main function for the action
-func Main(obj map[string]interface{}) map[string]interface{} {
-	name, ok := obj["name"].(string)
-	if !ok {
-		name = "world"
-	}
-	fmt.Printf("name=%s\n", name)
-	msg := make(map[string]interface{})
-	msg["main-standalone"] = "Hello, " + name + "!"
-	return msg
-}
diff --git a/main/proxy.go b/main/proxy.go
index 9674724..7f4b6bc 100644
--- a/main/proxy.go
+++ b/main/proxy.go
@@ -34,6 +34,9 @@ var debug = flag.Bool("debug", false, "enable debug output")
 // flag to require on-the-fly compilation
 var compile = flag.String("compile", "", "compile, reading in standard input the specified function, and producing the result in stdout")
 
+// flag to pass an environment as a json string
+var env = flag.String("env", "", "pass an environment as a json string")
+
 // fatal if error
 func fatalIf(err error) {
 	if err != nil {
@@ -62,7 +65,7 @@ func main() {
 
 	// compile on the fly upon request
 	if *compile != "" {
-		ap.ExtractAndCompileIO(os.Stdin, os.Stdout, *compile)
+		ap.ExtractAndCompileIO(os.Stdin, os.Stdout, *compile, *env)
 		return
 	}
 
diff --git a/openwhisk/actionProxy.go b/openwhisk/actionProxy.go
index bceab1a..c70ec28 100644
--- a/openwhisk/actionProxy.go
+++ b/openwhisk/actionProxy.go
@@ -103,6 +103,7 @@ func (ap *ActionProxy) SetEnv(env map[string]interface{}) {
 			ap.env[k] = string(buf)
 		}
 	}
+	Debug("init env: %s", ap.env)
 }
 
 // StartLatestAction tries to start
@@ -179,7 +180,7 @@ func (ap *ActionProxy) Start(port int) {
 }
 
 // ExtractAndCompileIO read in input and write in output to use the runtime as a compiler "on-the-fly"
-func (ap *ActionProxy) ExtractAndCompileIO(r io.Reader, w io.Writer, main string) {
+func (ap *ActionProxy) ExtractAndCompileIO(r io.Reader, w io.Writer, main string, env string) {
 
 	// read the std input
 	in, err := ioutil.ReadAll(r)
@@ -187,6 +188,12 @@ func (ap *ActionProxy) ExtractAndCompileIO(r io.Reader, w io.Writer, main string
 		log.Fatal(err)
 	}
 
+	envMap := make(map[string]interface{})
+	if env != "" {
+	    json.Unmarshal([]byte(env), &envMap)
+	}
+    ap.SetEnv(envMap)
+
 	// extract and compile it
 	file, err := ap.ExtractAndCompile(&in, main)
 	if err != nil {
diff --git a/openwhisk/actionProxy_test.go b/openwhisk/actionProxy_test.go
index e28772c..08853ac 100644
--- a/openwhisk/actionProxy_test.go
+++ b/openwhisk/actionProxy_test.go
@@ -92,7 +92,7 @@ func Example_compile_bin() {
 	dat, _ := Zip("_test/pysample")
 	inp := bytes.NewBuffer(dat)
 	out := new(bytes.Buffer)
-	ap.ExtractAndCompileIO(inp, out, "main")
+	ap.ExtractAndCompileIO(inp, out, "main", "")
 	Unzip(out.Bytes(), "./action/c1/out")
 	sys("_test/find.sh", "./action/c1/out")
 	// Output:
@@ -113,7 +113,7 @@ func Example_compile_src() {
 	dat, _ := Zip("_test/pysample/lib")
 	inp := bytes.NewBuffer(dat)
 	out := new(bytes.Buffer)
-	ap.ExtractAndCompileIO(inp, out, "main")
+	ap.ExtractAndCompileIO(inp, out, "main", "")
 	Unzip(out.Bytes(), "./action/c2/out")
 	sys("_test/find.sh", "./action/c2/out")
 	// Output:
diff --git a/openwhisk/compiler_test.go b/openwhisk/compiler_test.go
index ed91ad4..c2cc677 100644
--- a/openwhisk/compiler_test.go
+++ b/openwhisk/compiler_test.go
@@ -73,6 +73,8 @@ func Example_hello() {
 	N := "1"
 	sys(PREP, "hello1.src", N, "exec")
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
+	env := map[string]interface{}{"GOROOT": TMP + N}
+	ap.SetEnv(env)
 	ap.CompileAction("hello", TMP+N+"/src", TMP+N+"/bin")
 	sys(CHECK, TMP+N+"/bin/exec")
 	// Output:
@@ -86,6 +88,8 @@ func Example_package() {
 	N := "2"
 	sys(PREP, "hello2.src", N, "exec", "hello")
 	ap := NewActionProxy(TMP, COMP, os.Stdout, os.Stderr)
+	env := map[string]interface{}{"GOROOT": TMP + N}
+	ap.SetEnv(env)
 	ap.CompileAction("main", TMP+N+"/src", TMP+N+"/bin")
 	sys(CHECK, TMP+N+"/bin/exec")
 	// Output:
diff --git a/settings.gradle b/settings.gradle
index f202675..810ebb9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -20,6 +20,8 @@ include 'tests'
 include 'actionloop'
 include 'golang1.11'
 include 'golang1.12'
+include 'golang1.13'
+include 'golang1.15'
 
 rootProject.name = 'runtime-golang'
 
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo12Tests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo12Tests.scala
index 2973b59..7502a67 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo12Tests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo12Tests.scala
@@ -16,123 +16,16 @@
  */
 package runtime.actionContainers
 
-import actionContainers.ActionContainer.withContainer
-import actionContainers.{ActionContainer, BasicActionRunnerTests}
 import common.WskActorSystem
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
 @RunWith(classOf[JUnitRunner])
 class ActionLoopBasicGo12Tests
-    extends BasicActionRunnerTests
-    with WskActorSystem {
+    extends ActionLoopBasicGoTests
+      with WskActorSystem {
 
-  val goCompiler = "action-golang-v1.12"
-  val image = goCompiler
+  override lazy val goCompiler = "action-golang-v1.12"
+  override lazy val image = goCompiler
 
-  override def withActionContainer(env: Map[String, String] = Map.empty)(
-      code: ActionContainer => Unit) = {
-    withContainer(image, env)(code)
-  }
-
-  def withActionLoopContainer(code: ActionContainer => Unit) =
-    withContainer(image)(code)
-
-  behavior of image
-
-  override val testNoSourceOrExec = TestConfig("")
-
-  override val testNotReturningJson = TestConfig(
-    """
-      |package main
-      |import (
-      |	"bufio"
-      |	"fmt"
-      |	"os"
-      |)
-      |func main() {
-      |	reader := bufio.NewReader(os.Stdin)
-      |	out := os.NewFile(3, "pipe")
-      |	defer out.Close()
-      |	reader.ReadBytes('\n')
-      |	fmt.Fprintln(out, "\"a string but not a map\"")
-      |	reader.ReadBytes('\n')
-      |}
-    """.stripMargin)
-
-  override val testEcho = TestConfig(
-    """|package main
-       |import "fmt"
-       |import "log"
-       |func Main(args map[string]interface{}) map[string]interface{} {
-       | fmt.Println("hello stdout")
-       | log.Println("hello stderr")
-       | return args
-       |}
-    """.stripMargin)
-
-  override val testUnicode = TestConfig(
-    """|package main
-       |import "fmt"
-       |func Main(args map[string]interface{}) map[string]interface{} {
-       |	delimiter := args["delimiter"].(string)
-       |	str := delimiter + " ☃ " + delimiter
-       |  fmt.Println(str)
-       |	res := make(map[string]interface{})
-       |	res["winter"] = str
-       |	return res
-       |}
-       """.stripMargin)
-
-  override val testEnv = TestConfig(
-    """
-      |package main
-      |import "os"
-      |func Main(args map[string]interface{}) map[string]interface{} {
-      |	res := make(map[string]interface{})
-      |	res["api_host"] = os.Getenv("__OW_API_HOST")
-      |	res["api_key"] = os.Getenv("__OW_API_KEY")
-      |	res["namespace"] = os.Getenv("__OW_NAMESPACE")
-      |	res["action_name"] = os.Getenv("__OW_ACTION_NAME")
-      |	res["action_version"] = os.Getenv("__OW_ACTION_VERSION")
-      |	res["activation_id"] = os.Getenv("__OW_ACTIVATION_ID")
-      |	res["deadline"] = os.Getenv("__OW_DEADLINE")
-      |	return res
-      |}
-    """.stripMargin)
-
-  override val testEnvParameters = TestConfig(
-    """
-      |package main
-      |import "os"
-      |func Main(args map[string]interface{}) map[string]interface{} {
-      | res := make(map[string]interface{})
-      | res["SOME_VAR"] = os.Getenv("SOME_VAR")
-      | res["ANOTHER_VAR"] = os.Getenv("ANOTHER_VAR")
-      | return res
-      |}
-    """.stripMargin)
-
-  override val testInitCannotBeCalledMoreThanOnce = TestConfig(
-    """|package main
-       |func Main(args map[string]interface{}) map[string]interface{} {
-       | return args
-       |}
-    """.stripMargin)
-
-  override val testEntryPointOtherThanMain = TestConfig(
-    """|package main
-       |func Niam(args map[string]interface{}) map[string]interface{} {
-       | return args
-       |}
-    """.stripMargin,
-    main = "niam"
-  )
-
-  override val testLargeInput = TestConfig(
-    """|package main
-       |func Main(args map[string]interface{}) map[string]interface{} {
-       | return args
-       |}
-    """.stripMargin)
 }
diff --git a/examples/golang-main-package/src/main.go b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo13Tests.scala
similarity index 67%
copy from examples/golang-main-package/src/main.go
copy to tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo13Tests.scala
index 26dc66f..c5f9e5c 100644
--- a/examples/golang-main-package/src/main.go
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo13Tests.scala
@@ -14,16 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package runtime.actionContainers
 
-package main
+import common.WskActorSystem
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
 
-import (
-	"fmt"
-	"hello"
-)
+@RunWith(classOf[JUnitRunner])
+class ActionLoopBasicGo13Tests
+    extends ActionLoopBasicGoTests
+      with WskActorSystem {
 
-// Main forwading to Hello
-func Main(args map[string]interface{}) map[string]interface{} {
-	fmt.Println("Main")
-	return hello.Hello(args)
+  override lazy val goCompiler = "action-golang-v1.13"
+  override lazy val image = goCompiler
+  override lazy val requireAck = true
 }
diff --git a/examples/golang-main-package/src/main.go b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo15Tests.scala
similarity index 67%
rename from examples/golang-main-package/src/main.go
rename to tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo15Tests.scala
index 26dc66f..b3eb779 100644
--- a/examples/golang-main-package/src/main.go
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGo15Tests.scala
@@ -14,16 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package runtime.actionContainers
 
-package main
+import common.WskActorSystem
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
 
-import (
-	"fmt"
-	"hello"
-)
+@RunWith(classOf[JUnitRunner])
+class ActionLoopBasicGo15Tests
+    extends ActionLoopBasicGoTests
+      with WskActorSystem {
 
-// Main forwading to Hello
-func Main(args map[string]interface{}) map[string]interface{} {
-	fmt.Println("Main")
-	return hello.Hello(args)
+  override lazy val goCompiler = "action-golang-v1.15"
+  override lazy val image = goCompiler
+  override lazy val requireAck = true
 }
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala
index 3b41567..a9380be 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopBasicGoTests.scala
@@ -27,8 +27,9 @@ class ActionLoopBasicGoTests
     extends BasicActionRunnerTests
     with WskActorSystem {
 
-  val goCompiler = "action-golang-v1.11"
-  val image = goCompiler
+  lazy val goCompiler = "action-golang-v1.11"
+  lazy val image = goCompiler
+  lazy val requireAck = false
 
   override def withActionContainer(env: Map[String, String] = Map.empty)(
       code: ActionContainer => Unit) = {
@@ -43,21 +44,22 @@ class ActionLoopBasicGoTests
   override val testNoSourceOrExec = TestConfig("")
 
   override val testNotReturningJson = TestConfig(
-    """
-      |package main
-      |import (
-      |	"bufio"
-      |	"fmt"
-      |	"os"
-      |)
-      |func main() {
-      |	reader := bufio.NewReader(os.Stdin)
-      |	out := os.NewFile(3, "pipe")
-      |	defer out.Close()
-      |	reader.ReadBytes('\n')
-      |	fmt.Fprintln(out, "\"a string but not a map\"")
-      |	reader.ReadBytes('\n')
-      |}
+    s"""
+       |package main
+       |import (
+       |	"bufio"
+       |	"fmt"
+       |	"os"
+       |)
+       |func main() {
+       |	reader := bufio.NewReader(os.Stdin)
+       |	out := os.NewFile(3, "pipe")
+       |	defer out.Close()
+       |  ${if(requireAck) "fmt.Fprintf(out, `{ \"ok\": true}%s`, \"\\n\")" else ""}
+       |	reader.ReadBytes('\\n')
+       |	fmt.Fprintln(out, \"a string but not a map\")
+       |	reader.ReadBytes('\\n')
+       |}
     """.stripMargin)
 
   override val testEcho = TestConfig(
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopGo12ContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo12ContainerTests.scala
index b08ed6f..2e83682 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopGo12ContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo12ContainerTests.scala
@@ -17,127 +17,16 @@
 
 package runtime.actionContainers
 
-//import java.util.concurrent.TimeoutException
-import actionContainers.ActionContainer.withContainer
-import actionContainers.{ActionContainer, ActionProxyContainerTestUtils}
 import common.WskActorSystem
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
-//import spray.json.JsNumber
-//import spray.json.JsBoolean
-import spray.json.{JsObject, JsString}
-
 @RunWith(classOf[JUnitRunner])
 class ActionLoopGo12ContainerTests
-    extends ActionProxyContainerTestUtils
-    with WskActorSystem {
-
-  import GoResourceHelpers._
-
-  val goCompiler = "action-golang-v1.12"
-  val image = goCompiler
-
-  def withActionLoopContainer(code: ActionContainer => Unit) =
-    withContainer(image)(code)
-
-  behavior of image
-
-  def helloGo(main: String, pkg: String = "main") = {
-    val func = main.capitalize
-    s"""|package ${pkg}
-        |
-        |import "fmt"
-        |
-        |func ${func}(obj map[string]interface{}) map[string]interface{} {
-        |	 name, ok := obj["name"].(string)
-        |	 if !ok {
-        |	  	name = "Stranger"
-        |	 }
-        |	 fmt.Printf("name=%s\\n", name)
-        |  msg := make(map[string]interface{})
-        |	 msg["${pkg}-${main}"] = "Hello, " + name + "!"
-        |	 return msg
-        |}
-        |""".stripMargin
-  }
-
-   def helloSrc(main: String) = Seq(
-    Seq(s"${main}.go") -> helloGo(main)
-  )
-
-  def helloMsg(name: String = "Demo") =
-    runPayload(JsObject("name" -> JsString(name)))
-
-  def okMsg(key: String, value: String) =
-    200 -> Some(JsObject(key -> JsString(value)))
-
-  it should "run sample with init that does nothing" in {
-    val (out, err) = withActionLoopContainer { c =>
-      c.init(JsObject())._1 should be(403)
-      c.run(JsObject())._1 should be(500)
-    }
-  }
-
-  it should "accept a binary main" in {
-    val exe = ExeBuilder.mkBase64Zip(goCompiler, helloSrc("main"), "main")
-
-    withActionLoopContainer { c =>
-      c.init(initPayload(exe))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-main", "Hello, Demo!"))
-    }
-  }
-
-
-  it should "accept a src main action " in {
-    var src = ExeBuilder.mkBase64Src(helloSrc("main"))
-    withActionLoopContainer { c =>
-      c.init(initPayload(src))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-main", "Hello, Demo!"))
-    }
-  }
-
-  it should "accept a src not-main action " in {
-    var src = ExeBuilder.mkBase64Src(helloSrc("hello"))
-    withActionLoopContainer { c =>
-      c.init(initPayload(src, "hello"))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-hello", "Hello, Demo!"))
-    }
-  }
-
-  it should "accept a zipped src main action" in {
-    var src = ExeBuilder.mkBase64SrcZip(helloSrc("main"))
-    withActionLoopContainer { c =>
-      c.init(initPayload(src))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-main", "Hello, Demo!"))
-    }
-  }
+    extends ActionLoopGoContainerTests
+      with WskActorSystem {
 
-  it should "accept a zipped src not-main action" in {
-    var src = ExeBuilder.mkBase64SrcZip(helloSrc("hello"))
-    withActionLoopContainer { c =>
-      c.init(initPayload(src, "hello"))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("main-hello", "Hello, Demo!"))
-    }
-  }
+  override lazy val goCompiler = "action-golang-v1.12"
+  override lazy val image = goCompiler
 
-  it should "deploy a zip main src with subdir" in {
-    var src = ExeBuilder.mkBase64SrcZip(
-      Seq(
-        Seq("hello", "hello.go") -> helloGo("Hello", "hello"),
-        Seq("main.go") ->
-          """
-          |package main
-          |import "hello"
-          |func Main(args map[string]interface{})map[string]interface{} {
-          | return hello.Hello(args)
-          |}
-        """.stripMargin
-      )
-    )
-    withActionLoopContainer { c =>
-      c.init(initPayload(src))._1 shouldBe (200)
-      c.run(helloMsg()) should be(okMsg("hello-Hello", "Hello, Demo!"))
-    }
-  }
 }
diff --git a/examples/golang-hello-vendor/src/hello.go b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo13ContainerTests.scala
similarity index 69%
copy from examples/golang-hello-vendor/src/hello.go
copy to tests/src/test/scala/runtime/actionContainers/ActionLoopGo13ContainerTests.scala
index 6e477cd..97c3f0c 100644
--- a/examples/golang-hello-vendor/src/hello.go
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo13ContainerTests.scala
@@ -15,15 +15,19 @@
  * limitations under the License.
  */
 
-package main
+package runtime.actionContainers
 
-import (
-	"fmt"
-	"hello"
-)
+import common.WskActorSystem
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+
+@RunWith(classOf[JUnitRunner])
+class ActionLoopGo13ContainerTests
+    extends  ActionLoopGoContainerTests
+      with WskActorSystem {
+
+  override lazy val goCompiler = "action-golang-v1.13"
+  override lazy val image = goCompiler
 
-// Main forwading to Hello
-func Hello(args map[string]interface{}) map[string]interface{} {
-	fmt.Println("Entering Hello")
-	return hello.Hello(args)
 }
diff --git a/examples/golang-hello-vendor/src/hello.go b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo15ContainerTests.scala
similarity index 69%
rename from examples/golang-hello-vendor/src/hello.go
rename to tests/src/test/scala/runtime/actionContainers/ActionLoopGo15ContainerTests.scala
index 6e477cd..7ed7fa2 100644
--- a/examples/golang-hello-vendor/src/hello.go
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopGo15ContainerTests.scala
@@ -15,15 +15,19 @@
  * limitations under the License.
  */
 
-package main
+package runtime.actionContainers
 
-import (
-	"fmt"
-	"hello"
-)
+import common.WskActorSystem
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+
+
+@RunWith(classOf[JUnitRunner])
+class ActionLoopGo15ContainerTests
+    extends ActionLoopGoContainerTests
+      with WskActorSystem {
+
+  override lazy val goCompiler = "action-golang-v1.15"
+  override lazy val image = goCompiler
 
-// Main forwading to Hello
-func Hello(args map[string]interface{}) map[string]interface{} {
-	fmt.Println("Entering Hello")
-	return hello.Hello(args)
 }
diff --git a/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala b/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala
index 2c3422c..b23a5dc 100644
--- a/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala
+++ b/tests/src/test/scala/runtime/actionContainers/ActionLoopGoContainerTests.scala
@@ -17,15 +17,12 @@
 
 package runtime.actionContainers
 
-//import java.util.concurrent.TimeoutException
 import actionContainers.{ActionContainer, ActionProxyContainerTestUtils}
 import actionContainers.ActionContainer.withContainer
 import common.WskActorSystem
 import org.junit.runner.RunWith
 import org.scalatest.junit.JUnitRunner
 
-//import spray.json.JsNumber
-//import spray.json.JsBoolean
 import spray.json.{JsObject, JsString}
 
 @RunWith(classOf[JUnitRunner])
@@ -35,8 +32,8 @@ class ActionLoopGoContainerTests
 
   import GoResourceHelpers._
 
-  val goCompiler = "action-golang-v1.11"
-  val image = goCompiler
+  lazy val goCompiler = "action-golang-v1.11"
+  lazy val image = goCompiler
 
   def withActionLoopContainer(code: ActionContainer => Unit) =
     withContainer(image)(code)
@@ -125,6 +122,7 @@ class ActionLoopGoContainerTests
     var src = ExeBuilder.mkBase64SrcZip(
       Seq(
         Seq("hello", "hello.go") -> helloGo("Hello", "hello"),
+        Seq("hello", "go.mod") -> "module hello\n",
         Seq("main.go") ->
           """
           |package main
@@ -132,7 +130,8 @@ class ActionLoopGoContainerTests
           |func Main(args map[string]interface{})map[string]interface{} {
           | return hello.Hello(args)
           |}
-        """.stripMargin
+        """.stripMargin,
+        Seq("go.mod") -> "module action\nreplace hello => ./hello\nrequire hello v0.0.0-00010101000000-000000000000\n"
       )
     )
     withActionLoopContainer { c =>
diff --git a/tools/travis/publish.sh b/tools/travis/publish.sh
index 57e7cbe..98564d6 100755
--- a/tools/travis/publish.sh
+++ b/tools/travis/publish.sh
@@ -28,10 +28,8 @@ if [[ ! -z ${DOCKER_USER} ]] && [[ ! -z ${DOCKER_PASSWORD} ]]; then
 docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 fi
 
-if [ ${RUNTIME_VERSION} == "1.11" ]; then
-  RUNTIME="golang1.11"
-elif [ ${RUNTIME_VERSION} == "1.12" ]; then
-  RUNTIME="golang1.12"
+if [[ ${RUNTIME_VERSION} =~ 1\.[0-9]+ ]]; then
+  RUNTIME="golang$RUNTIME_VERSION"
 elif [ ${RUNTIME_VERSION} == "actionloop" ]; then
   RUNTIME="actionloop"
 fi