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

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


The following commit(s) were added to refs/heads/master by this push:
     new 9ba89ac  Summary updates for actions without annotated descriptions: 
(#2490)
9ba89ac is described below

commit 9ba89ac3754c63a139608eca053e156b68a203be
Author: Brandon Lee Underwood <brandon.lee.underw...@ibm.com>
AuthorDate: Thu Aug 10 21:36:31 2017 -0400

    Summary updates for actions without annotated descriptions: (#2490)
    
    * Added '(parameters: none defined)' when getting entity with no parameters
    * Function builds generic description from parameters
    * Added testing for Actions, Triggers, and Packages
    * Finalized actions now denoted by "*"
    * Update help file to reflect action summary changes
    * Parameters marked as bound and final
    * Bound parameters prefixed by "*", finalized parameters denoted by "**"
    * Testing for trigger/action/package get summary cases, including bound and 
finalized for actions
    * Updated docs
---
 docs/actions.md                                    |  18 +-
 docs/packages.md                                   |  55 +++--
 .../whisk/core/cli/test/WskBasicUsageTests.scala   | 245 +++++++++++++++++++++
 tools/cli/go-whisk-cli/commands/action.go          |   2 +-
 tools/cli/go-whisk-cli/commands/package.go         |   2 +-
 tools/cli/go-whisk-cli/commands/trigger.go         |   2 +-
 tools/cli/go-whisk-cli/commands/util.go            |  91 +++++++-
 .../go-whisk-cli/wski18n/resources/en_US.all.json  |  12 +-
 8 files changed, 388 insertions(+), 39 deletions(-)

diff --git a/docs/actions.md b/docs/actions.md
index 7570b9e..4073154 100644
--- a/docs/actions.md
+++ b/docs/actions.md
@@ -484,12 +484,18 @@ Several utility actions are provided in a package called 
`/whisk.system/utils` t
   ```
   ```
   package /whisk.system/utils: Building blocks that format and assemble data
-   action /whisk.system/utils/head: Extract prefix of an array
-   action /whisk.system/utils/split: Split a string into an array
-   action /whisk.system/utils/sort: Sorts an array
-   action /whisk.system/utils/echo: Returns the input
-   action /whisk.system/utils/date: Current date and time
-   action /whisk.system/utils/cat: Concatenates input into a string
+   (parameters: none defined)
+     action /whisk.system/utils/namespace: Returns namespace for the 
authorization key used to invoke this action
+       (parameters: none defined)
+     action /whisk.system/utils/date: Current date and time
+       (parameters: none defined)
+     action /whisk.system/utils/sort: Sorts an array
+       (parameters: lines)
+     action /whisk.system/utils/split: Split a string into an array
+       (parameters: payload, separator)
+     action /whisk.system/utils/hosturl: Returns the URL to activation an 
action or trigger
+       (parameters: ext, path, trigger, web)
+     ...
   ```
 
   You will be using the `split` and `sort` actions in this example.
diff --git a/docs/packages.md b/docs/packages.md
index 499c247..d4811f1 100644
--- a/docs/packages.md
+++ b/docs/packages.md
@@ -42,15 +42,21 @@ Several packages are registered with OpenWhisk. You can get 
a list of packages i
   ```
   ```
   package /whisk.system/cloudant: Cloudant database service
-     (params: BluemixServiceName host username password dbname includeDoc 
overwrite)
+     (parameters: *apihost, *dbname, *host, overwrite, *password, *username)
    action /whisk.system/cloudant/read: Read document from database
-   action /whisk.system/cloudant/write: Write document to database
+     (parameters: dbname, id, params)
+   action /whisk.system/cloudant/write: Write document in database
+     (parameters: dbname, doc)
    feed   /whisk.system/cloudant/changes: Database change feed
+     (parameters: dbname, filter, query_params)
+  ...
   ```
 
-  This output shows that the Cloudant package provides two actions, `read` and 
`write`, and one trigger feed called `changes`. The `changes` feed causes 
triggers to be fired when documents are added to the specified Cloudant 
database.
+  **Note**: Parameters listed under the package with a prefix `*` are 
predefined, bound parameters. Parameters without a `*` are those listed under 
the [annotations](./annotations.md) for each entity. Furthermore, any 
parameters with the prefix `**` are finalized bound parameters. This means that 
they are immutable, and cannot be changed by the user. Any entity listed under 
a package inherits specific bound parameters from the package. To view the list 
of known parameters of an entity be [...]
+
+  This output shows that the Cloudant package provides the actions `read` and 
`write`, and the trigger feed called `changes`. The `changes` feed causes 
triggers to be fired when documents are added to the specified Cloudant 
database.
 
-  The Cloudant package also defines the parameters `username`, `password`, 
`host`, and `port`. These parameters must be specified for the actions and 
feeds to be meaningful. The parameters allow the actions to operate on a 
specific Cloudant account, for example.
+  The Cloudant package also defines the parameters `username`, `password`, 
`host`, and `dbname`. These parameters must be specified for the actions and 
feeds to be meaningful. The parameters allow the actions to operate on a 
specific Cloudant account, for example.
 
 3. Get a description of the `/whisk.system/cloudant/read` action.
 
@@ -59,10 +65,12 @@ Several packages are registered with OpenWhisk. You can get 
a list of packages i
   ```
   ```
   action /whisk.system/cloudant/read: Read document from database
-     (params: dbname includeDoc id)
+     (parameters: *apihost, *dbname, *host, *id, params, *password, *username)
   ```
 
-  This output shows that the Cloudant `read` action requires three parameters, 
including the database and document ID to retrieve.
+  *NOTE*: Notice that the parameters listed for the action `read` were 
expanded upon from the action summary compared to the package summary above. To 
see the official bound parameters for actions and triggers listed under 
packages, run an individual get summary for the particular entity.
+
+  This output shows that the Cloudant `read` action lists eight parameters, 
seven of which are predefined. These include the database and document ID to 
retrieve.
 
 
 ## Invoking actions in a package
@@ -75,8 +83,8 @@ You can invoke actions in a package, just as with other 
actions. The next few st
   $ wsk action get --summary /whisk.system/samples/greeting
   ```
   ```
-  action /whisk.system/samples/greeting: Print a friendly greeting
-     (params: name place)
+  action /whisk.system/samples/greeting: Returns a friendly greeting
+     (parameters: name, place)
   ```
 
   Notice that the `greeting` action takes two parameters: `name` and `place`.
@@ -131,11 +139,16 @@ In the following simple example, you bind to the 
`/whisk.system/samples` package
   $ wsk package get --summary valhallaSamples
   ```
   ```
-  package /myNamespace/valhallaSamples
-   action /myNamespace/valhallaSamples/greeting: Returns a friendly greeting
-   action /myNamespace/valhallaSamples/wordCount: Count words in a string
-   action /myNamespace/valhallaSamples/helloWorld: Demonstrates logging 
facilities
-   action /myNamespace/valhallaSamples/curl: Curl a host url
+  package /namespace/valhallaSamples: Returns a result based on parameter place
+     (parameters: *place)
+   action /namespace/valhallaSamples/helloWorld: Demonstrates logging 
facilities
+      (parameters: payload)
+   action /namespace/valhallaSamples/greeting: Returns a friendly greeting
+      (parameters: name, place)
+   action /namespace/valhallaSamples/curl: Curl a host url
+      (parameters: payload)
+   action /namespace/valhallaSamples/wordCount: Count words in a string
+      (parameters: payload)
   ```
 
   Notice that all the actions in the `/whisk.system/samples` package are 
available in the `valhallaSamples` package binding.
@@ -177,8 +190,10 @@ Feeds offer a convenient way to configure an external 
event source to fire these
   $ wsk package get --summary /whisk.system/alarms
   ```
   ```
-  package /whisk.system/alarms
-   feed   /whisk.system/alarms/alarm
+  package /whisk.system/alarms: Alarms and periodic utility
+     (parameters: *apihost, *cron, *trigger_payload)
+   feed   /whisk.system/alarms/alarm: Fire trigger when alarm occurs
+      (parameters: none defined)
   ```
 
   ```
@@ -186,12 +201,13 @@ Feeds offer a convenient way to configure an external 
event source to fire these
   ```
   ```
   action /whisk.system/alarms/alarm: Fire trigger when alarm occurs
-     (params: cron trigger_payload)
+     (parameters: *apihost, *cron, *trigger_payload)
   ```
 
   The `/whisk.system/alarms/alarm` feed takes two parameters:
   - `cron`: A crontab specification of when to fire the trigger.
   - `trigger_payload`: The payload parameter value to set in each trigger 
event.
+  - `apihost`: The API host endpoint that will be receiving the feed.
 
 2. Create a trigger that fires every eight seconds.
 
@@ -257,6 +273,7 @@ To create a custom package with a simple action in it, try 
the following example
   ```
   ```
   package /myNamespace/custom
+     (parameters: none defined)
   ```
 
   Notice that the package is empty.
@@ -285,7 +302,9 @@ To create a custom package with a simple action in it, try 
the following example
   ```
   ```
   package /myNamespace/custom
+    (parameters: none defined)
    action /myNamespace/custom/identity
+    (parameters: none defined)
   ```
 
   You can see the `custom/identity` action in your namespace now.
@@ -411,8 +430,10 @@ Others can now use your `custom` package, including 
binding to the package or di
   $ wsk package get --summary custom
   ```
   ```
-  package /myNamespace/custom
+  package /myNamespace/custom: Returns a result based on parameters city and 
country
+     (parameters: *city, *country)
    action /myNamespace/custom/identity
+     (parameters: none defined)
   ```
 
   In the previous example, you're working with the `myNamespace` namespace, 
and this namespace appears in the fully qualified name.
diff --git a/tests/src/test/scala/whisk/core/cli/test/WskBasicUsageTests.scala 
b/tests/src/test/scala/whisk/core/cli/test/WskBasicUsageTests.scala
index 8ebb1bf..59ede45 100644
--- a/tests/src/test/scala/whisk/core/cli/test/WskBasicUsageTests.scala
+++ b/tests/src/test/scala/whisk/core/cli/test/WskBasicUsageTests.scala
@@ -706,6 +706,97 @@ class WskBasicUsageTests
             msg.r.findAllIn(notTruncated).length shouldBe 0
     }
 
+    it should "denote bound and finalized action parameters for action 
summaries" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val nameBoundParams = "actionBoundParams"
+            val nameFinalParams = "actionFinalParams"
+            val paramAnnot = "paramAnnot"
+            val paramOverlap = "paramOverlap"
+            val paramBound = "paramBound"
+            val annots = Map(
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString(paramAnnot),
+                        "description" -> JsString("Annotated")),
+                    JsObject(
+                        "name" -> JsString(paramOverlap),
+                        "description" -> JsString("Annotated And Bound"))))
+            val annotsFinal = Map(
+                "final" -> JsBoolean(true),
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString(paramAnnot),
+                        "description" -> JsString("Annotated Parameter 
description")),
+                    JsObject(
+                        "name" -> JsString(paramOverlap),
+                        "description" -> JsString("Annotated And Bound"))))
+            val paramsBound = Map(
+                paramBound -> JsString("Bound"),
+                paramOverlap -> JsString("Bound And Annotated"))
+
+            assetHelper.withCleaner(wsk.action, nameBoundParams) {
+                (action, _) =>
+                    action.create(nameBoundParams, defaultAction, annotations 
= annots, parameters = paramsBound)
+            }
+            assetHelper.withCleaner(wsk.action, nameFinalParams) {
+                (action, _) =>
+                    action.create(nameFinalParams, defaultAction, annotations 
= annotsFinal, parameters = paramsBound)
+            }
+
+            val stdoutBound = wsk.action.get(nameBoundParams, summary = 
true).stdout
+            val stdoutFinal = wsk.action.get(nameFinalParams, summary = 
true).stdout
+
+            stdoutBound should include (
+                s"(parameters: $paramAnnot, *$paramBound, *$paramOverlap)")
+            stdoutFinal should include (
+                s"(parameters: $paramAnnot, **$paramBound, **$paramOverlap)")
+    }
+
+    it should "create, and get an action summary without a description and/or 
defined parameters" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val actNameNoParams = "actionNoParams"
+            val actNameNoDesc = "actionNoDesc"
+            val actNameNoDescOrParams = "actionNoDescOrParams"
+            val desc = "Action description"
+            val descFromParamsResp = "Returns a result based on parameters"
+            val annotsNoParams = Map(
+                "description" -> JsString(desc)
+            )
+            val annotsNoDesc = Map(
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString("paramName1"),
+                        "description" -> JsString("Parameter description 1")),
+                    JsObject(
+                        "name" -> JsString("paramName2"),
+                        "description" -> JsString("Parameter description 2"))))
+
+            assetHelper.withCleaner(wsk.action, actNameNoDesc) {
+                (action, _) =>
+                    action.create(actNameNoDesc, defaultAction, annotations = 
annotsNoDesc)
+            }
+            assetHelper.withCleaner(wsk.action, actNameNoParams) {
+                (action, _) =>
+                    action.create(actNameNoParams, defaultAction, annotations 
= annotsNoParams)
+            }
+            assetHelper.withCleaner(wsk.action, actNameNoDescOrParams) {
+                (action, _) =>
+                    action.create(actNameNoDescOrParams, defaultAction)
+            }
+
+            val stdoutNoDesc = wsk.action.get(actNameNoDesc, summary = 
true).stdout
+            val stdoutNoParams = wsk.action.get(actNameNoParams, summary = 
true).stdout
+            val stdoutNoDescOrParams = wsk.action.get(actNameNoDescOrParams, 
summary = true).stdout
+            val namespace = wsk.namespace.whois()
+
+            stdoutNoDesc should include regex (
+                s"(?i)action /${namespace}/${actNameNoDesc}: 
${descFromParamsResp} paramName1 and paramName2\\s*\\(parameters: paramName1, 
paramName2\\)")
+            stdoutNoParams should include regex (
+                s"(?i)action /${namespace}/${actNameNoParams}: 
${desc}\\s*\\(parameters: none defined\\)")
+            stdoutNoDescOrParams should include regex (
+                s"(?i)action 
/${namespace}/${actNameNoDescOrParams}\\s*\\(parameters: none defined\\)")
+    }
+
     behavior of "Wsk packages"
 
     it should "create, and delete a package" in {
@@ -802,6 +893,83 @@ class WskBasicUsageTests
 
     }
 
+    it should "create, and get a package summary without a description and/or 
parameters" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val pkgNoDesc = "pkgNoDesc"
+            val pkgNoParams = "pkgNoParams"
+            val pkgNoDescOrParams = "pkgNoDescOrParams"
+            val pkgDesc = "Package description"
+            val descFromParams = "Returns a result based on parameters"
+            val namespace = wsk.namespace.whois()
+            val qualpkgNoDesc = s"/${namespace}/${pkgNoDesc}"
+            val qualpkgNoParams = s"/${namespace}/${pkgNoParams}"
+            val qualpkgNoDescOrParams = s"/${namespace}/${pkgNoDescOrParams}"
+
+            val pkgAnnotsNoParams = Map(
+                "description" -> JsString(pkgDesc)
+            )
+            val pkgAnnotsNoDesc = Map(
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString("paramName1"),
+                        "description" -> JsString("Parameter description 1")),
+                    JsObject(
+                        "name" -> JsString("paramName2"),
+                        "description" -> JsString("Parameter description 2"))))
+
+            assetHelper.withCleaner(wsk.pkg, pkgNoDesc) {
+                (pkg, _) =>
+                    pkg.create(pkgNoDesc, annotations = pkgAnnotsNoDesc)
+            }
+            assetHelper.withCleaner(wsk.pkg, pkgNoParams) {
+                (pkg, _) =>
+                    pkg.create(pkgNoParams, annotations = pkgAnnotsNoParams)
+            }
+            assetHelper.withCleaner(wsk.pkg, pkgNoDescOrParams) {
+                (pkg, _) =>
+                    pkg.create(pkgNoDescOrParams)
+            }
+
+            val stdoutNoDescPkg = wsk.pkg.get(pkgNoDesc, summary = true).stdout
+            val stdoutNoParamsPkg = wsk.pkg.get(pkgNoParams, summary = 
true).stdout
+            val stdoutNoDescOrParams = wsk.pkg.get(pkgNoDescOrParams, summary 
= true).stdout
+
+            stdoutNoDescPkg should include regex (
+                s"(?i)package ${qualpkgNoDesc}: ${descFromParams} paramName1 
and paramName2\\s*\\(parameters: paramName1, paramName2\\)")
+            stdoutNoParamsPkg should include regex (
+                s"(?i)package ${qualpkgNoParams}: ${pkgDesc}\\s*\\(parameters: 
none defined\\)")
+            stdoutNoDescOrParams should include regex (
+                s"(?i)package ${qualpkgNoDescOrParams}\\s*\\(parameters: none 
defined\\)")
+    }
+
+    it should "denote bound package parameters for package summaries" in 
withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val pkgBoundParams = "pkgBoundParams"
+            val pkgParamAnnot = "pkgParamAnnot"
+            val pkgParamOverlap = "pkgParamOverlap"
+            val pkgParamBound = "pkgParamBound"
+            val pkgAnnots = Map(
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString(pkgParamAnnot),
+                        "description" -> JsString("Annotated")),
+                    JsObject(
+                        "name" -> JsString(pkgParamOverlap),
+                        "description" -> JsString("Annotated And Bound"))))
+            val pkgParamsBound = Map(
+                pkgParamBound -> JsString("Bound"),
+                pkgParamOverlap -> JsString("Bound And Annotated"))
+
+            assetHelper.withCleaner(wsk.pkg, pkgBoundParams) {
+                (pkg, _) =>
+                    pkg.create(pkgBoundParams, annotations = pkgAnnots, 
parameters = pkgParamsBound)
+            }
+
+            val pkgStdoutBound = wsk.pkg.get(pkgBoundParams, summary = 
true).stdout
+
+            pkgStdoutBound should include (s"(parameters: $pkgParamAnnot, 
*$pkgParamBound, *$pkgParamOverlap)")
+    }
+
     behavior of "Wsk triggers"
 
     it should "create, and get a trigger to verify parameter and annotation 
parsing" in withAssetCleaner(wskprops) {
@@ -900,6 +1068,83 @@ class WskBasicUsageTests
             }
     }
 
+    it should "denote bound trigger parameters for trigger summaries" in 
withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val trgBoundParams = "trgBoundParams"
+            val trgParamAnnot = "trgParamAnnot"
+            val trgParamOverlap = "trgParamOverlap"
+            val trgParamBound = "trgParamBound"
+            val trgAnnots = Map(
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString(trgParamAnnot),
+                        "description" -> JsString("Annotated")),
+                    JsObject(
+                        "name" -> JsString(trgParamOverlap),
+                        "description" -> JsString("Annotated And Bound"))))
+            val trgParamsBound = Map(
+                trgParamBound -> JsString("Bound"),
+                trgParamOverlap -> JsString("Bound And Annotated"))
+
+            assetHelper.withCleaner(wsk.trigger, trgBoundParams) {
+                (trigger, _) =>
+                    trigger.create(trgBoundParams, annotations = trgAnnots, 
parameters = trgParamsBound)
+            }
+
+            val trgStdoutBound = wsk.trigger.get(trgBoundParams, summary = 
true).stdout
+
+            trgStdoutBound should include (s"(parameters: $trgParamAnnot, 
*$trgParamBound, *$trgParamOverlap)")
+    }
+
+    it should "create, and get a trigger summary without a description and/or 
parameters" in withAssetCleaner(wskprops) {
+        (wp, assetHelper) =>
+            val trgNoDesc = "trgNoDesc"
+            val trgNoParams = "trgNoParams"
+            val trgNoDescOrParams = "trgNoDescOrParams"
+            val trgDesc = "Package description"
+            val descFromParams = "Returns a result based on parameters"
+            val namespace = wsk.namespace.whois()
+            val qualtrgNoDesc = s"/${namespace}/${trgNoDesc}"
+            val qualtrgNoParams = s"/${namespace}/${trgNoParams}"
+            val qualtrgNoDescOrParams = s"/${namespace}/${trgNoDescOrParams}"
+
+            val trgAnnotsNoParams = Map(
+                "description" -> JsString(trgDesc)
+            )
+            val trgAnnotsNoDesc = Map(
+                "parameters" -> JsArray(
+                    JsObject(
+                        "name" -> JsString("paramName1"),
+                        "description" -> JsString("Parameter description 1")),
+                    JsObject(
+                        "name" -> JsString("paramName2"),
+                        "description" -> JsString("Parameter description 2"))))
+
+            assetHelper.withCleaner(wsk.trigger, trgNoDesc) {
+                (trigger, _) =>
+                    trigger.create(trgNoDesc, annotations = trgAnnotsNoDesc)
+            }
+            assetHelper.withCleaner(wsk.trigger, trgNoParams) {
+                (trigger, _) =>
+                    trigger.create(trgNoParams, annotations = 
trgAnnotsNoParams)
+            }
+            assetHelper.withCleaner(wsk.trigger, trgNoDescOrParams) {
+                (trigger, _) =>
+                    trigger.create(trgNoDescOrParams)
+            }
+
+            val stdoutNoDescPkg = wsk.trigger.get(trgNoDesc, summary = 
true).stdout
+            val stdoutNoParamsPkg = wsk.trigger.get(trgNoParams, summary = 
true).stdout
+            val stdoutNoDescOrParams = wsk.trigger.get(trgNoDescOrParams, 
summary = true).stdout
+
+            stdoutNoDescPkg should include regex (
+                s"(?i)trigger ${qualtrgNoDesc}: ${descFromParams} paramName1 
and paramName2\\s*\\(parameters: paramName1, paramName2\\)")
+            stdoutNoParamsPkg should include regex (
+                s"(?i)trigger ${qualtrgNoParams}: ${trgDesc}\\s*\\(parameters: 
none defined\\)")
+            stdoutNoDescOrParams should include regex (
+                s"(?i)trigger ${qualtrgNoDescOrParams}\\s*\\(parameters: none 
defined\\)")
+    }
+
     behavior of "Wsk entity list formatting"
 
     it should "create, and list a package with a long name" in 
withAssetCleaner(wskprops) {
diff --git a/tools/cli/go-whisk-cli/commands/action.go 
b/tools/cli/go-whisk-cli/commands/action.go
index 714f72e..33fd5ab 100644
--- a/tools/cli/go-whisk-cli/commands/action.go
+++ b/tools/cli/go-whisk-cli/commands/action.go
@@ -936,7 +936,7 @@ func init() {
     actionInvokeCmd.Flags().BoolVarP(&flags.common.blocking, "blocking", "b", 
false, wski18n.T("blocking invoke"))
     actionInvokeCmd.Flags().BoolVarP(&flags.action.result, "result", "r", 
false, wski18n.T("blocking invoke; show only activation result (unless there is 
a failure)"))
 
-    actionGetCmd.Flags().BoolVarP(&flags.common.summary, "summary", "s", 
false, wski18n.T("summarize action details"))
+    actionGetCmd.Flags().BoolVarP(&flags.common.summary, "summary", "s", 
false, wski18n.T("summarize action details; parameters with prefix \"*\" are 
bound, \"**\" are bound and finalized"))
     actionGetCmd.Flags().BoolVarP(&flags.action.url, "url", "r", false, 
wski18n.T("get action url"))
 
     actionListCmd.Flags().IntVarP(&flags.common.skip, "skip", "s", 0, 
wski18n.T("exclude the first `SKIP` number of actions from the result"))
diff --git a/tools/cli/go-whisk-cli/commands/package.go 
b/tools/cli/go-whisk-cli/commands/package.go
index e88b8bb..7680fcf 100644
--- a/tools/cli/go-whisk-cli/commands/package.go
+++ b/tools/cli/go-whisk-cli/commands/package.go
@@ -514,7 +514,7 @@ func init() {
   packageUpdateCmd.Flags().StringVarP(&flags.common.paramFile, "param-file", 
"P", "", wski18n.T("`FILE` containing parameter values in JSON format"))
   packageUpdateCmd.Flags().StringVar(&flags.common.shared, "shared", "", 
wski18n.T("package visibility `SCOPE`; yes = shared, no = private"))
 
-  packageGetCmd.Flags().BoolVarP(&flags.common.summary, "summary", "s", false, 
wski18n.T("summarize package details"))
+  packageGetCmd.Flags().BoolVarP(&flags.common.summary, "summary", "s", false, 
wski18n.T("summarize package details; parameters with prefix \"*\" are bound"))
 
   packageBindCmd.Flags().StringSliceVarP(&flags.common.annotation, 
"annotation", "a", []string{}, wski18n.T("annotation values in `KEY VALUE` 
format"))
   packageBindCmd.Flags().StringVarP(&flags.common.annotFile, 
"annotation-file", "A", "", wski18n.T("`FILE` containing annotation values in 
JSON format"))
diff --git a/tools/cli/go-whisk-cli/commands/trigger.go 
b/tools/cli/go-whisk-cli/commands/trigger.go
index c85229d..4f94451 100644
--- a/tools/cli/go-whisk-cli/commands/trigger.go
+++ b/tools/cli/go-whisk-cli/commands/trigger.go
@@ -503,7 +503,7 @@ func init() {
     triggerUpdateCmd.Flags().StringSliceVarP(&flags.common.param, "param", 
"p", []string{}, wski18n.T("parameter values in `KEY VALUE` format"))
     triggerUpdateCmd.Flags().StringVarP(&flags.common.paramFile, "param-file", 
"P", "", wski18n.T("`FILE` containing parameter values in JSON format"))
 
-    triggerGetCmd.Flags().BoolVarP(&flags.trigger.summary, "summary", "s", 
false, wski18n.T("summarize trigger details"))
+    triggerGetCmd.Flags().BoolVarP(&flags.trigger.summary, "summary", "s", 
false, wski18n.T("summarize trigger details; parameters with prefix \"*\" are 
bound"))
 
     triggerFireCmd.Flags().StringSliceVarP(&flags.common.param, "param", "p", 
[]string{}, wski18n.T("parameter values in `KEY VALUE` format"))
     triggerFireCmd.Flags().StringVarP(&flags.common.paramFile, "param-file", 
"P", "", wski18n.T("`FILE` containing parameter values in JSON format"))
diff --git a/tools/cli/go-whisk-cli/commands/util.go 
b/tools/cli/go-whisk-cli/commands/util.go
index cbae2c4..3ef9ff0 100644
--- a/tools/cli/go-whisk-cli/commands/util.go
+++ b/tools/cli/go-whisk-cli/commands/util.go
@@ -386,14 +386,15 @@ func printArrayContents(arrStr []string) {
 func printPackageSummary(pkg *whisk.Package) {
     printEntitySummary(fmt.Sprintf("%7s", "package"), 
getFullName(pkg.Namespace, pkg.Name, ""),
         getValueString(pkg.Annotations, "description"),
-        strings.Join(getChildValueStrings(pkg.Annotations, "parameters", 
"name"), ", "))
+        strings.Join(getParamUnion(pkg.Annotations, pkg.Parameters, "name"), 
", "))
 
 
     if pkg.Actions != nil {
         for _, action := range pkg.Actions {
+            paramUnion := getParamUnion(action.Annotations, action.Parameters, 
"name")
             printEntitySummary(fmt.Sprintf("%7s", "action"), 
getFullName(pkg.Namespace, pkg.Name, action.Name),
                 getValueString(action.Annotations, "description"),
-                strings.Join(getChildValueStrings(action.Annotations, 
"parameters", "name"), ", "))
+                strings.Join(paramUnion, ", "))
         }
     }
 
@@ -401,23 +402,24 @@ func printPackageSummary(pkg *whisk.Package) {
         for _, feed := range pkg.Feeds {
             printEntitySummary(fmt.Sprintf("%7s", "feed  "), 
getFullName(pkg.Namespace, pkg.Name, feed.Name),
                 getValueString(feed.Annotations, "description"),
-                strings.Join(getChildValueStrings(feed.Annotations, 
"parameters", "name"), ", "))
+                strings.Join(getParamUnion(feed.Annotations, feed.Parameters, 
"name"), ", "))
         }
     }
 }
 
 func printActionSummary(action *whisk.Action) {
+    paramUnion := getParamUnion(action.Annotations, action.Parameters, "name")
     printEntitySummary(fmt.Sprintf("%6s", "action"),
         getFullName(action.Namespace, "", action.Name),
         getValueString(action.Annotations, "description"),
-        strings.Join(getChildValueStrings(action.Annotations, "parameters", 
"name"), ", "))
+        strings.Join(paramUnion, ", "))
 }
 
 func printTriggerSummary(trigger *whisk.Trigger) {
     printEntitySummary(fmt.Sprintf("%7s", "trigger"),
         getFullName(trigger.Namespace, "", trigger.Name),
         getValueString(trigger.Annotations, "description"),
-        strings.Join(getChildValueStrings(trigger.Annotations, "parameters", 
"name"), ", "))
+        strings.Join(getParamUnion(trigger.Annotations, trigger.Parameters, 
"name"), ", "))
 }
 
 func printRuleSummary(rule *whisk.Rule) {
@@ -427,15 +429,74 @@ func printRuleSummary(rule *whisk.Rule) {
 }
 
 func printEntitySummary(entityType string, fullName string, description 
string, params string) {
+    emptyParams := "none defined"
+    if len(params) <= 0 {
+        params = emptyParams
+    }
     if len(description) > 0 {
         fmt.Fprintf(color.Output, "%s %s: %s\n", boldString(entityType), 
fullName, description)
+    } else if params != emptyParams {
+        descriptionFromParams := buildParamDescription(params)
+        fmt.Fprintf(color.Output, "%s %s: %s\n", boldString(entityType), 
fullName, descriptionFromParams)
     } else {
         fmt.Fprintf(color.Output, "%s %s\n", boldString(entityType), fullName)
     }
+    fmt.Fprintf(color.Output, "   (%s: %s)\n", 
boldString(wski18n.T("parameters")), params)
+}
+
+//  getParamUnion(keyValArrAnnots, keyValArrParams, key) returns the union
+//      of parameters listed under annotations (keyValArrAnnots, using key) and
+//      bound parameters (keyValArrParams). Bound parameters will be denoted 
with
+//      a prefixed "*", and finalized bound parameters (can't be changed by
+//      user) will be denoted by a prefixed "**".
+func getParamUnion(keyValArrAnnots whisk.KeyValueArr, keyValArrParams 
whisk.KeyValueArr, key string) []string {
+    var res []string
+    tag := "*"
+    if getValueBool(keyValArrAnnots, "final") {
+        tag = "**"
+    }
+    boundParams := getKeys(keyValArrParams)
+    annotatedParams := getChildValueStrings(keyValArrAnnots, "parameters", key)
+    res = append(boundParams, annotatedParams...)       // Create union of 
boundParams and annotatedParams with duplication
+    for i := 0; i < len(res); i++ {
+        for j := i + 1; j < len(res); j++ {
+            if res[i] == res[j] {
+                res = append(res[:j], res[j+1:]...)     // Remove duplicate 
entry
+            }
+        }
+    }
+    sort.Strings(res)
+    res = tagBoundParams(boundParams, res, tag)
+    return res
+}
 
-    if len(params) > 0 {
-        fmt.Fprintf(color.Output, "   (%s: %s)\n", 
boldString(wski18n.T("parameters")), params)
+//  tagBoundParams(boundParams, paramUnion, tag) returns the list paramUnion 
with
+//      all strings listed under boundParams set with a prefix tag.
+func tagBoundParams(boundParams []string, paramUnion []string, tag string) 
[]string {
+    res := paramUnion
+    for i := 0; i < len(boundParams); i++ {
+        for j := 0; j < len(res); j++ {
+            if boundParams[i] == res[j] {
+                res[j] = fmt.Sprintf("%s%s", tag, res[j])
+            }
+        }
     }
+    return res
+}
+
+//  buildParamDescription(params) returns a default entity description for
+//      `$ wsk [ENTITY] get [ENTITY_NAME] --summary` when parameters are 
defined,
+//      but the entity description under annotations is not.
+func buildParamDescription(params string) string {
+    preamble := "Returns a result based on parameter"
+    params = strings.Replace(params, "*", "", -1)
+    temp := strings.Split(params, ",")
+    if len(temp) > 1 {
+        lastParam := temp[len(temp) - 1]
+        newParams := strings.Replace(params, fmt.Sprintf(",%s", lastParam), 
fmt.Sprintf(" and%s", lastParam), 1)
+        return fmt.Sprintf("%ss %s", preamble, newParams)
+    }
+    return fmt.Sprintf("%s %s", preamble, params)
 }
 
 func getFullName(namespace string, packageName string, entityName string) 
(string) {
@@ -503,6 +564,22 @@ func getValueString(keyValueArr whisk.KeyValueArr, key 
string) (string) {
     return res
 }
 
+func getValueBool(keyValueArr whisk.KeyValueArr, key string) (bool) {
+    var value interface{}
+    var res bool
+
+    value = keyValueArr.GetValue(key)
+    castedValue, canCast := value.(bool)
+
+    if (canCast) {
+        res = castedValue
+    }
+
+    whisk.Debug(whisk.DbgInfo, "Got bool value '%v' for key '%s'\n", res, key)
+
+    return res
+}
+
 func getChildValues(keyValueArr whisk.KeyValueArr, key string, childKey 
string) ([]interface{}) {
     var value interface{}
     var res []interface{}
diff --git a/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json 
b/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json
index 2140b9e..78acda0 100644
--- a/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json
+++ b/tools/cli/go-whisk-cli/wski18n/resources/en_US.all.json
@@ -221,8 +221,8 @@
     "translation": "package visibility `SCOPE`; yes = shared, no = private"
   },
   {
-    "id": "summarize package details",
-    "translation": "summarize package details"
+    "id": "summarize package details; parameters with prefix \"*\" are bound",
+    "translation": "summarize package details; parameters with prefix \"*\" 
are bound"
   },
   {
     "id": "include publicly shared entities in the result",
@@ -700,8 +700,8 @@
     "translation": "trigger feed `ACTION_NAME`"
   },
   {
-    "id": "summarize trigger details",
-    "translation": "summarize trigger details"
+    "id": "summarize trigger details; parameters with prefix \"*\" are bound",
+    "translation": "summarize trigger details; parameters with prefix \"*\" 
are bound"
   },
   {
     "id": "parameter values in `KEY VALUE` format",
@@ -952,8 +952,8 @@
     "translation": "only return `LIMIT` number of actions from the collection"
   },
   {
-    "id": "summarize action details",
-    "translation": "summarize action details"
+    "id": "summarize action details; parameters with prefix \"*\" are bound, 
\"**\" are bound and finalized",
+    "translation": "summarize action details; parameters with prefix \"*\" are 
bound, \"**\" are bound and finalized"
   },
   {
     "id": "work with activations",

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

Reply via email to