Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow optional leading slash in CLI commands #2424

Merged
merged 1 commit into from
Aug 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ You can create your own namespaces if you're entitled to do so. The `/whisk.syst
### Fully qualified names

The fully qualified name of an entity is
`/namespaceName[/packageName]/entityName`. Notice that `/` is used to delimit namespaces, packages, and entities. Also, namespaces must be prefixed with a `/`.
`/namespaceName[/packageName]/entityName`. Notice that `/` is used to delimit namespaces, packages, and entities.

If the fully qualified name has three parts:
`/namespaceName/packageName/entityName`, then the namespace can be entered without a prefixed `/`; otherwise, namespaces must be prefixed with a `/`.

For convenience, the namespace can be left off if it is the user's *default namespace*.

Expand Down Expand Up @@ -219,23 +222,23 @@ The following packages are available to be used in the Node.js 6.9.1 environment
- [glob v7.1.1](https://www.npmjs.com/package/glob) - Match files using the patterns the shell uses, like stars and stuff.
- [gm v1.23.0](https://www.npmjs.com/package/gm) - GraphicsMagick and ImageMagick for Node.
- [lodash v4.17.2](https://www.npmjs.com/package/lodash) - The Lodash library exported as Node.js modules.
- [log4js v0.6.38](https://www.npmjs.com/package/log4js) - This is a conversion of the log4js framework to work with Node.
- [log4js v0.6.38](https://www.npmjs.com/package/log4js) - This is a conversion of the log4js framework to work with Node.
- [iconv-lite v0.4.15](https://www.npmjs.com/package/iconv-lite) - Pure JS character encoding conversion
- [marked v0.3.6](https://www.npmjs.com/package/marked) - A full-featured markdown parser and compiler, written in JavaScript. Built for speed.
- [merge v1.2.0](https://www.npmjs.com/package/merge) - Merge multiple objects into one, optionally creating a new cloned object.
- [merge v1.2.0](https://www.npmjs.com/package/merge) - Merge multiple objects into one, optionally creating a new cloned object.
- [moment v2.17.0](https://www.npmjs.com/package/moment) - A lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.
- [mongodb v2.2.11](https://www.npmjs.com/package/mongodb) - The official MongoDB driver for Node.js.
- [mustache v2.3.0](https://www.npmjs.com/package/mustache) - mustache.js is an implementation of the mustache template system in JavaScript.
- [nano v6.2.0](https://www.npmjs.com/package/nano) - minimalistic couchdb driver for Node.js.
- [node-uuid v1.4.7](https://www.npmjs.com/package/node-uuid) - Deprecated UUID packaged.
- [node-uuid v1.4.7](https://www.npmjs.com/package/node-uuid) - Deprecated UUID packaged.
- [nodemailer v2.6.4](https://www.npmjs.com/package/nodemailer) - Send e-mails from Node.js – easy as cake!
- [oauth2-server v2.4.1](https://www.npmjs.com/package/oauth2-server) - Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in Node.js.
- [openwhisk v3.3.2](https://www.npmjs.com/package/openwhisk) - JavaScript client library for the OpenWhisk platform. Provides a wrapper around the OpenWhisk APIs.
- [pkgcloud v1.4.0](https://www.npmjs.com/package/pkgcloud) - pkgcloud is a standard library for Node.js that abstracts away differences among multiple cloud providers.
- [process v0.11.9](https://www.npmjs.com/package/process) - require('process'); just like any other module.
- [pug v2.0.0-beta6](https://www.npmjs.com/package/pug) - Implements the Pug templating language.
- [redis v2.6.3](https://www.npmjs.com/package/redis) - This is a complete and feature rich Redis client for Node.js.
- [request v2.79.0](https://www.npmjs.com/package/request) - Request is designed to be the simplest way possible to make HTTP calls.
- [redis v2.6.3](https://www.npmjs.com/package/redis) - This is a complete and feature rich Redis client for Node.js.
- [request v2.79.0](https://www.npmjs.com/package/request) - Request is designed to be the simplest way possible to make HTTP calls.
- [request-promise v4.1.1](https://www.npmjs.com/package/request-promise) - The simplified HTTP request client 'request' with Promise support. Powered by Bluebird.
- [rimraf v2.5.4](https://www.npmjs.com/package/rimraf) - The UNIX command rm -rf for node.
- [semver v5.3.0](https://www.npmjs.com/package/semver) - Supports semantic versioning.
Expand All @@ -251,10 +254,10 @@ The following packages are available to be used in the Node.js 6.9.1 environment
- [uuid v3.0.0](https://www.npmjs.com/package/uuid) - Simple, fast generation of RFC4122 UUIDS.
- [validator v6.1.0](https://www.npmjs.com/package/validator) - A library of string validators and sanitizers.
- [watson-developer-cloud v2.29.0](https://www.npmjs.com/package/watson-developer-cloud) - Node.js client library to use the Watson Developer Cloud services, a collection of APIs that use cognitive computing to solve complex problems.
- [when v3.7.7](https://www.npmjs.com/package/when) - When.js is a rock solid, battle-tested Promises/A+ and when() implementation, including a complete ES6 Promise shim.
- [when v3.7.7](https://www.npmjs.com/package/when) - When.js is a rock solid, battle-tested Promises/A+ and when() implementation, including a complete ES6 Promise shim.
- [winston v2.3.0](https://www.npmjs.com/package/winston) - A multi-transport async logging library for node.js. "CHILL WINSTON! ... I put it in the logs."
- [ws v1.1.1](https://www.npmjs.com/package/ws) - ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and server implementation.
- [xml2js v0.4.17](https://www.npmjs.com/package/xml2js) - Simple XML to JavaScript object converter. It supports bi-directional conversion.
- [xml2js v0.4.17](https://www.npmjs.com/package/xml2js) - Simple XML to JavaScript object converter. It supports bi-directional conversion.
- [xmlhttprequest v1.8.0](https://www.npmjs.com/package/xmlhttprequest) - node-XMLHttpRequest is a wrapper for the built-in http client to emulate the browser XMLHttpRequest object.
- [yauzl v2.7.0](https://www.npmjs.com/package/yauzl) - yet another unzip library for node. For zipping.

Expand Down
2 changes: 1 addition & 1 deletion tests/src/test/scala/common/Wsk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ trait FullyQualifiedNames {
*/
def fqn(name: String)(implicit wp: WskProps) = {
val sep = "/" // Namespace.PATHSEP
if (name.startsWith(sep)) name
if (name.startsWith(sep) || name.count(_ == sep(0)) == 2) name
else s"$sep${wp.namespace}$sep$name"
}

Expand Down
1 change: 0 additions & 1 deletion tests/src/test/scala/system/basic/WskActionTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -355,5 +355,4 @@ class WskActionTests
activation.logs.get.mkString(" ") should include(s"hello $utf8")
}
}

}
29 changes: 29 additions & 0 deletions tests/src/test/scala/whisk/core/cli/test/WskBasicUsageTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,35 @@ class WskBasicUsageTests
result.stderr should include regex ("""(?i)Run 'wsk --help' for usage""")
}

it should "allow a 3 part Fully Qualified Name (FQN) without a leading '/'" in withAssetCleaner(wskprops) {
(wp, assetHelper) =>
val guestNamespace = wsk.namespace.whois()
val packageName = "packageName3ptFQN"
val actionName = "actionName3ptFQN"
val triggerName = "triggerName3ptFQN"
val ruleName = "ruleName3ptFQN"
val fullQualifiedName = s"${guestNamespace}/${packageName}/${actionName}"
// Used for action and rule creation below
assetHelper.withCleaner(wsk.pkg, packageName) {
(pkg, _) => pkg.create(packageName)
}
assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, _) => trigger.create(triggerName)
}
// Test action and rule creation where action name is 3 part FQN w/out leading slash
assetHelper.withCleaner(wsk.action, fullQualifiedName) {
(action, _) => action.create(fullQualifiedName, defaultAction)
}
assetHelper.withCleaner(wsk.rule, ruleName) {
(rule, _) =>
rule.create(ruleName, trigger = triggerName, action = fullQualifiedName)
}

wsk.action.invoke(fullQualifiedName).stdout should include(s"ok: invoked /$fullQualifiedName")
wsk.action.get(fullQualifiedName).stdout should include(s"ok: got action ${packageName}/${actionName}")
}


behavior of "Wsk actions"

it should "reject creating entities with invalid names" in withAssetCleaner(wskprops) {
Expand Down
108 changes: 54 additions & 54 deletions tools/cli/go-whisk-cli/commands/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ var actionInvokeCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
var err error
var parameters interface{}
var qualifiedName QualifiedName
var qualifiedName = new(QualifiedName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please go through all of the command files and make sure the proper replacements have been made for the QualifiedName functions that you have added.

qualifiedName.packageName line 235
printActionGetWithURL(qualifiedName.entity, actionURL) line 236

var paramArgs []string

if whiskErr := checkArgs(
Expand All @@ -133,11 +133,11 @@ var actionInvokeCmd = &cobra.Command{
return whiskErr
}

if qualifiedName, err = parseQualifiedName(args[0]); err != nil {
return parseQualifiedNameError(args[0], err)
if qualifiedName, err = NewQualifiedName(args[0]); err != nil {
return NewQualifiedNameError(args[0], err)
}

client.Namespace = qualifiedName.namespace
client.Namespace = qualifiedName.GetNamespace()
paramArgs = flags.common.param

if len(paramArgs) > 0 {
Expand All @@ -148,12 +148,12 @@ var actionInvokeCmd = &cobra.Command{
if flags.action.result {flags.common.blocking = true}

res, _, err := client.Actions.Invoke(
qualifiedName.entityName,
qualifiedName.GetEntityName(),
parameters,
flags.common.blocking,
flags.action.result)

return handleInvocationResponse(qualifiedName, parameters, res, err)
return handleInvocationResponse(*qualifiedName, parameters, res, err)
},
}

Expand All @@ -164,29 +164,29 @@ func handleInvocationResponse(
err error) (error) {
if err == nil {
printInvocationMsg(
qualifiedName.namespace,
qualifiedName.entityName,
qualifiedName.GetNamespace(),
qualifiedName.GetEntityName(),
getValueFromJSONResponse(ACTIVATION_ID, result),
result,
color.Output)
} else {
if !flags.common.blocking {
return handleInvocationError(err, qualifiedName.entityName, parameters)
return handleInvocationError(err, qualifiedName.GetEntityName(), parameters)
} else {
if isBlockingTimeout(err) {
printBlockingTimeoutMsg(
qualifiedName.namespace,
qualifiedName.entityName,
qualifiedName.GetNamespace(),
qualifiedName.GetEntityName(),
getValueFromJSONResponse(ACTIVATION_ID, result))
} else if isApplicationError(err) {
printInvocationMsg(
qualifiedName.namespace,
qualifiedName.entityName,
qualifiedName.GetNamespace(),
qualifiedName.GetEntityName(),
getValueFromJSONResponse(ACTIVATION_ID, result),
result,
colorable.NewColorableStderr())
} else {
return handleInvocationError(err, qualifiedName.entityName, parameters)
return handleInvocationError(err, qualifiedName.GetEntityName(), parameters)
}
}
}
Expand All @@ -204,7 +204,7 @@ var actionGetCmd = &cobra.Command{
var err error
var field string
var action *whisk.Action
var qualifiedName QualifiedName
var qualifiedName = new(QualifiedName)

if whiskErr := checkArgs(args, 1, 2, "Action get", wski18n.T("An action name is required.")); whiskErr != nil {
return whiskErr
Expand All @@ -218,29 +218,29 @@ var actionGetCmd = &cobra.Command{
}
}

if qualifiedName, err = parseQualifiedName(args[0]); err != nil {
return parseQualifiedNameError(args[0], err)
if qualifiedName, err = NewQualifiedName(args[0]); err != nil {
return NewQualifiedNameError(args[0], err)
}

client.Namespace = qualifiedName.namespace
client.Namespace = qualifiedName.GetNamespace()

if action, _, err = client.Actions.Get(qualifiedName.entityName); err != nil {
return actionGetError(qualifiedName.entityName, err)
if action, _, err = client.Actions.Get(qualifiedName.GetEntityName()); err != nil {
return actionGetError(qualifiedName.GetEntityName(), err)
}

if flags.action.url {
actionURL := action.ActionURL(Properties.APIHost,
DefaultOpenWhiskApiPath,
Properties.APIVersion,
qualifiedName.packageName)
printActionGetWithURL(qualifiedName.entity, actionURL)
qualifiedName.GetPackageName())
printActionGetWithURL(qualifiedName.GetEntity(), actionURL)
} else if flags.common.summary {
printSummary(action)
} else {
if len(field) > 0 {
printActionGetWithField(qualifiedName.entityName, field, action)
printActionGetWithField(qualifiedName.GetEntityName(), field, action)
} else {
printActionGet(qualifiedName.entityName, action)
printActionGet(qualifiedName.GetEntityName(), action)
}
}

Expand All @@ -255,7 +255,7 @@ var actionDeleteCmd = &cobra.Command{
SilenceErrors: true,
PreRunE: setupClientConfig,
RunE: func(cmd *cobra.Command, args []string) error {
var qualifiedName QualifiedName
var qualifiedName = new(QualifiedName)
var err error

if whiskErr := checkArgs(
Expand All @@ -267,17 +267,17 @@ var actionDeleteCmd = &cobra.Command{
return whiskErr
}

if qualifiedName, err = parseQualifiedName(args[0]); err != nil {
return parseQualifiedNameError(args[0], err)
if qualifiedName, err = NewQualifiedName(args[0]); err != nil {
return NewQualifiedNameError(args[0], err)
}

client.Namespace = qualifiedName.namespace
client.Namespace = qualifiedName.GetNamespace()

if _, err = client.Actions.Delete(qualifiedName.entityName); err != nil {
return actionDeleteError(qualifiedName.entityName, err)
if _, err = client.Actions.Delete(qualifiedName.GetEntityName()); err != nil {
return actionDeleteError(qualifiedName.GetEntityName(), err)
}

printActionDeleted(qualifiedName.entityName)
printActionDeleted(qualifiedName.GetEntityName())

return nil
},
Expand All @@ -290,7 +290,7 @@ var actionListCmd = &cobra.Command{
SilenceErrors: true,
PreRunE: setupClientConfig,
RunE: func(cmd *cobra.Command, args []string) error {
var qualifiedName QualifiedName
var qualifiedName = new(QualifiedName)
var actions []whisk.Action
var err error

Expand All @@ -304,20 +304,20 @@ var actionListCmd = &cobra.Command{
}

if len(args) == 1 {
if qualifiedName, err = parseQualifiedName(args[0]); err != nil {
return parseQualifiedNameError(args[0], err)
if qualifiedName, err = NewQualifiedName(args[0]); err != nil {
return NewQualifiedNameError(args[0], err)
}

client.Namespace = qualifiedName.namespace
client.Namespace = qualifiedName.GetNamespace()
}

options := &whisk.ActionListOptions{
Skip: flags.common.skip,
Limit: flags.common.limit,
}

if actions, _, err = client.Actions.List(qualifiedName.entityName, options); err != nil {
return actionListError(qualifiedName.entityName, options, err)
if actions, _, err = client.Actions.List(qualifiedName.GetEntityName(), options); err != nil {
return actionListError(qualifiedName.GetEntityName(), options, err)
}

printList(actions)
Expand All @@ -334,16 +334,16 @@ func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action,
var parameters interface{}
var annotations interface{}

qualifiedName := QualifiedName{}
var qualifiedName = new(QualifiedName)

if qualifiedName, err = parseQualifiedName(args[0]); err != nil {
return nil, parseQualifiedNameError(args[0], err)
if qualifiedName, err = NewQualifiedName(args[0]); err != nil {
return nil, NewQualifiedNameError(args[0], err)
}

client.Namespace = qualifiedName.namespace
client.Namespace = qualifiedName.GetNamespace()
action := new(whisk.Action)
action.Name = qualifiedName.entityName
action.Namespace = qualifiedName.namespace
action.Name = qualifiedName.GetEntityName()
action.Namespace = qualifiedName.GetNamespace()
action.Limits = getLimits(
cmd.LocalFlags().Changed(MEMORY_FLAG),
cmd.LocalFlags().Changed(LOG_SIZE_FLAG),
Expand Down Expand Up @@ -372,19 +372,19 @@ func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action,
}

if flags.action.copy {
copiedQualifiedName := QualifiedName{}
var copiedQualifiedName = new(QualifiedName)

if copiedQualifiedName, err = parseQualifiedName(args[1]); err != nil {
return nil, parseQualifiedNameError(args[1], err)
if copiedQualifiedName, err = NewQualifiedName(args[1]); err != nil {
return nil, NewQualifiedNameError(args[1], err)
}

client.Namespace = copiedQualifiedName.namespace
client.Namespace = copiedQualifiedName.GetNamespace()

if existingAction, _, err = client.Actions.Get(copiedQualifiedName.entityName); err != nil {
return nil, actionGetError(copiedQualifiedName.entityName, err)
if existingAction, _, err = client.Actions.Get(copiedQualifiedName.GetEntityName()); err != nil {
return nil, actionGetError(copiedQualifiedName.GetEntityName(), err)
}

client.Namespace = qualifiedName.namespace
client.Namespace = qualifiedName.GetNamespace()
action.Exec = existingAction.Exec
action.Parameters = append(action.Parameters, existingAction.Parameters...)
action.Annotations = append(action.Annotations, existingAction.Annotations...)
Expand All @@ -407,7 +407,7 @@ func parseAction(cmd *cobra.Command, args []string, update bool) (*whisk.Action,

if cmd.LocalFlags().Changed(WEB_FLAG) {
preserveAnnotations := action.Annotations == nil
action.Annotations, err = webAction(flags.action.web, action.Annotations, qualifiedName.entityName, preserveAnnotations)
action.Annotations, err = webAction(flags.action.web, action.Annotations, qualifiedName.GetEntityName(), preserveAnnotations)
}

whisk.Debug(whisk.DbgInfo, "Parsed action struct: %#v\n", action)
Expand Down Expand Up @@ -874,10 +874,10 @@ func isWebAction(client *whisk.Client, qname QualifiedName) (error) {
var err error = nil

savedNs := client.Namespace
client.Namespace = qname.namespace
fullActionName := "/" + qname.namespace + "/" + qname.entityName
client.Namespace = qname.GetNamespace()
fullActionName := "/" + qname.GetNamespace() + "/" + qname.GetEntityName()

action, _, err := client.Actions.Get(qname.entityName)
action, _, err := client.Actions.Get(qname.GetEntityName())

if err != nil {
whisk.Debug(whisk.DbgError, "client.Actions.Get(%s) error: %s\n", fullActionName, err)
Expand Down
Loading