Repository: apache/incubator-openwhisk-client-js (js)

Issue:
Support passing annotations for rules
Related: https://github.com/apache/incubator-openwhisk-cli/issues/426

I inspected the `rules` code and there doesn't seem to be any code that will pass on annotations. 

Looks like `ruleBody`:
https://github.com/apache/incubator-openwhisk-client-js/blob/e772a2fd0811f4a2c7a0cc4e832c4d08e192b320/lib/rules.js#L35
should accept annotations in the options like `actions.js`:
https://github.com/apache/incubator-openwhisk-client-js/blob/e772a2fd0811f4a2c7a0cc4e832c4d08e192b320/lib/actions.js#L76

Pull request description:
Add annotation support for rules, triggers and packages.
This was missing but looking at the API and CLI should can be used with the following resources.

Fixes #165

Patch:
diff --git a/README.md b/README.md
index 010e509..4c61d03 100644
--- a/README.md
+++ b/README.md
@@ -516,6 +516,7 @@ ow.triggers.update({name: '...'})
 The following optional parameters are supported:
 - `trigger` - JSON object containing parameters for the trigger body (default: `{}`)
 - `namespace` - set custom namespace for endpoint
+- `annotations` - object containing annotations for the trigger (default: `{}`)
 
 ### create & update packages
 
@@ -527,6 +528,7 @@ ow.packages.update({name: '...'})
 The following optional parameters are supported:
 - `package` - JSON object containing parameters for the package body (default: `{}`)
 - `namespace` - set custom namespace for endpoint
+- `annotations` - object containing annotations for the package (default: `{}`)
 
 ### create & update rule
 
@@ -541,6 +543,7 @@ appended in the request, unless a fully qualified name is passed in
 
 The following optional parameters are supported:
 - `namespace` - set namespace for rule
+- `annotations` - object containing annotations for the rule (default: `{}`)
 
 ### enable & disable rule
 
diff --git a/lib/actions.js b/lib/actions.js
index 276c0fa..059e112 100644
--- a/lib/actions.js
+++ b/lib/actions.js
@@ -119,10 +119,6 @@ class Actions extends Resources {
       body.limits = options.limits
     }
 
-    if (typeof options.annotations === 'object') {
-      body.annotations = Object.keys(options.annotations).map(key => ({ key, value: options.annotations[key] }))
-    }
-
     return body
   }
 }
diff --git a/lib/resources.js b/lib/resources.js
index 627eed8..2246ef7 100644
--- a/lib/resources.js
+++ b/lib/resources.js
@@ -45,6 +45,11 @@ class Resources extends BaseOperation {
   }
 
   create (options) {
+    if (options && typeof options.annotations === 'object') {
+      const annotations = this.parseAnnotations(options.annotations)
+      options.body = Object.assign({ annotations }, options.body)
+    }
+
     return this.operationWithId('PUT', options)
   }
 
@@ -98,6 +103,10 @@ class Resources extends BaseOperation {
     return options.namespace
   }
 
+  parseAnnotations (annotations) {
+    return Object.keys(annotations).map(key => ({ key, value: annotations[key] }))
+  }
+
   retrieveId (options) {
     options = options || {}
     const id = this.identifiers.find(name => options.hasOwnProperty(name))


Test patch:
diff --git a/test/unit/packages.test.js b/test/unit/packages.test.js
index c4a52c9..2f7fd6a 100644
--- a/test/unit/packages.test.js
+++ b/test/unit/packages.test.js
@@ -190,6 +190,27 @@ test('should create a new package with parameters', t => {
   return packages.create({ name: id, 'package': pkg })
 })
 
+test('create a new package with annotations', t => {
+  t.plan(3)
+  const ns = '_'
+  const client = {}
+  const id = '12345'
+  const annotations = {
+    foo: 'bar'
+  }
+  const packages = new Packages(client)
+
+  client.request = (method, path, options) => {
+    t.is(method, 'PUT')
+    t.is(path, `namespaces/${ns}/packages/${id}`)
+    t.deepEqual(options.body, { annotations: [
+      { key: 'foo', value: 'bar' }
+    ] })
+  }
+
+  return packages.create({ name: id, annotations })
+})
+
 test('should update an existing package', t => {
   t.plan(4)
   const ns = '_'
diff --git a/test/unit/rules.test.js b/test/unit/rules.test.js
index 7a73a71..125b29d 100644
--- a/test/unit/rules.test.js
+++ b/test/unit/rules.test.js
@@ -178,6 +178,34 @@ test('create a new rule using fully qualified names', t => {
   return rules.create({ name, action, trigger })
 })
 
+test('create a new rule with annotations', t => {
+  t.plan(4)
+  const ns = '_'
+  const client = {}
+  const annotations = {
+    foo: 'bar'
+  }
+  const rules = new Rules(client)
+
+  const name = '12345'
+  const action = '/hello/some_action'
+  const trigger = '/hello/some_trigger'
+
+  client.request = (method, path, options) => {
+    t.is(method, 'PUT')
+    t.is(path, `namespaces/${ns}/rules/${name}`)
+    t.deepEqual(options.qs, {})
+    t.deepEqual(options.body, {
+      action,
+      trigger,
+      annotations: [
+        { key: 'foo', value: 'bar' }
+      ] })
+  }
+
+  return rules.create({ name, action, trigger, annotations })
+})
+
 test('create a rule without providing a rule name', t => {
   const client = { options: {} }
   const rules = new Rules(client)
diff --git a/test/unit/triggers.test.js b/test/unit/triggers.test.js
index 792050a..3b99277 100644
--- a/test/unit/triggers.test.js
+++ b/test/unit/triggers.test.js
@@ -252,3 +252,24 @@ test('create a new trigger with custom body', t => {
 
   return triggers.create({ name: '12345', trigger })
 })
+
+test('create a new trigger with annotations', t => {
+  t.plan(4)
+  const ns = '_'
+  const client = {}
+  const annotations = {
+    foo: 'bar'
+  }
+  const triggers = new Triggers(client)
+
+  client.request = (method, path, options) => {
+    t.is(method, 'PUT')
+    t.is(path, `namespaces/${ns}/triggers/12345`)
+    t.deepEqual(options.qs, {})
+    t.deepEqual(options.body, { annotations: [
+      { key: 'foo', value: 'bar' }
+    ] })
+  }
+
+  return triggers.create({ name: '12345', annotations })
+})