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

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


The following commit(s) were added to refs/heads/master by this push:
     new de4e3d8  Refactoring ManifestReader (#863)
de4e3d8 is described below

commit de4e3d80046ef691d91c4bf24b462c39916f5195
Author: Priti Desai <pde...@us.ibm.com>
AuthorDate: Tue Apr 10 13:28:16 2018 -0700

    Refactoring ManifestReader (#863)
    
    * cleaning up manifestreader
    
    * adding error messages to wski18n
    
    * adding integration test on actions
    
    * Adding trigger tests
    
    * adding error message for trigger
    
    * adding rule test
    
    * fixing integration test
    
    * fixing integration test
    
    * integration test fix
    
    * dropping doc on errors
---
 cmd/root.go                                        |  16 +-
 deployers/manifestreader.go                        | 290 ++++++++-----------
 deployers/manifestreader_test.go                   | 319 ++++++++++++++++++++-
 deployers/servicedeployer.go                       |   2 -
 parsers/manifest_parser.go                         |   6 +-
 tests/dat/manifest_validate_action_all.yaml        |  43 +++
 tests/dat/manifest_validate_dependencies.yaml      |  42 +++
 .../dat/manifest_validate_dependencies_bogus.yaml  |  42 +++
 ...st_validate_package_inputs_and_annotations.yaml |  37 +++
 tests/dat/manifest_validate_rules_bogus.yaml       |  41 +++
 tests/dat/manifest_validate_sequences_bogus.yaml   |  38 +++
 tests/dat/manifest_validate_triggers_bogus.yaml    |  33 +++
 utils/dependencies.go                              |  10 +
 utils/gitreader.go                                 |   1 -
 wski18n/i18n_ids.go                                |  47 +--
 wski18n/i18n_resources.go                          |   4 +-
 wski18n/resources/en_US.all.json                   |  24 ++
 17 files changed, 777 insertions(+), 218 deletions(-)

diff --git a/cmd/root.go b/cmd/root.go
index 77b2e03..4d665dd 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -150,7 +150,7 @@ func loadDefaultDeploymentFileFromProjectPath(command 
string, projectPath string
        } else if _, err := os.Stat(path.Join(projectPath, 
utils.DeploymentFileNameYml)); err == nil {
                utils.Flags.DeploymentPath = path.Join(projectPath, 
utils.DeploymentFileNameYml)
        }
-       displayCommandUsingFilenameMessage(command, wski18n.DEPLOYMENT_FILE, 
utils.Flags.ManifestPath)
+       displayCommandUsingFilenameMessage(command, wski18n.DEPLOYMENT_FILE, 
utils.Flags.DeploymentPath)
        return nil
 }
 
@@ -167,14 +167,19 @@ func Deploy() error {
        projectPath, _ := filepath.Abs(project_Path)
 
        // If manifest filename is not provided, attempt to load default 
manifests from project path
+       // default manifests are manifest.yaml and manifest.yml
+       // return failure if none of the default manifest files were found
        if utils.Flags.ManifestPath == "" {
                if err := 
loadDefaultManifestFileFromProjectPath(wski18n.CMD_DEPLOY, projectPath); err != 
nil {
                        return err
                }
        }
 
+       // If deployment filename is not provided, attempt to load default 
deployment files from project path
+       // default deployments are deployment.yaml and deployment.yml
+       // continue processing manifest file, even if none of the default
+       // deployment files were found as deployment files are optional
        if utils.Flags.DeploymentPath == "" {
-
                if err := 
loadDefaultDeploymentFileFromProjectPath(wski18n.CMD_DEPLOY, projectPath); err 
!= nil {
                        return err
                }
@@ -182,7 +187,9 @@ func Deploy() error {
 
        if utils.MayExists(utils.Flags.ManifestPath) {
 
+               // Create an instance of ServiceDeployer
                var deployer = deployers.NewServiceDeployer()
+               // Set Project Path, Manifest Path, and Deployment Path of 
ServiceDeployer
                deployer.ProjectPath = projectPath
                deployer.ManifestPath = utils.Flags.ManifestPath
                deployer.DeploymentPath = utils.Flags.DeploymentPath
@@ -191,6 +198,7 @@ func Deploy() error {
                // master record of any dependency that has been downloaded
                deployer.DependencyMaster = 
make(map[string]utils.DependencyRecord)
 
+               // Read credentials from Configuration file, manifest file or 
deployment file
                clientConfig, error := deployers.NewWhiskConfig(
                        utils.Flags.CfgFile,
                        utils.Flags.DeploymentPath,
@@ -210,14 +218,14 @@ func Deploy() error {
                // The auth, apihost and namespace have been chosen, so that we 
can check the supported runtimes here.
                setSupportedRuntimes(clientConfig.Host)
 
+               // Construct Deployment Plan
                err := deployer.ConstructDeploymentPlan()
-
                if err != nil {
                        return err
                }
 
+               // Deploy all OW entities
                err = deployer.Deploy()
-
                if err != nil {
                        return err
                } else {
diff --git a/deployers/manifestreader.go b/deployers/manifestreader.go
index 1f9171d..c19fd68 100644
--- a/deployers/manifestreader.go
+++ b/deployers/manifestreader.go
@@ -18,13 +18,14 @@
 package deployers
 
 import (
-       "errors"
        "strings"
 
+       "fmt"
        "github.com/apache/incubator-openwhisk-client-go/whisk"
        "github.com/apache/incubator-openwhisk-wskdeploy/parsers"
        "github.com/apache/incubator-openwhisk-wskdeploy/utils"
        "github.com/apache/incubator-openwhisk-wskdeploy/wskderrors"
+       "github.com/apache/incubator-openwhisk-wskdeploy/wski18n"
 )
 
 var clientConfig *whisk.Config
@@ -58,32 +59,31 @@ func (reader *ManifestReader) InitPackages(manifestParser 
*parsers.YAMLParser, m
                return err
        }
        reader.SetPackages(packages)
-
        return nil
 }
 
 // Wrapper parser to handle yaml dir
-func (deployer *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, 
manifestParser *parsers.YAMLParser, manifest *parsers.YAML, managedAnnotations 
whisk.KeyValue) error {
+func (reader *ManifestReader) HandleYaml(sdeployer *ServiceDeployer, 
manifestParser *parsers.YAMLParser, manifest *parsers.YAML, managedAnnotations 
whisk.KeyValue) error {
 
        var err error
        var manifestName = manifest.Filepath
 
-       deps, err := 
manifestParser.ComposeDependenciesFromAllPackages(manifest, 
deployer.serviceDeployer.ProjectPath, deployer.serviceDeployer.ManifestPath, 
managedAnnotations)
+       deps, err := 
manifestParser.ComposeDependenciesFromAllPackages(manifest, 
reader.serviceDeployer.ProjectPath, reader.serviceDeployer.ManifestPath, 
managedAnnotations)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, 
deployer.serviceDeployer.ManifestPath, managedAnnotations)
+       actions, err := manifestParser.ComposeActionsFromAllPackages(manifest, 
reader.serviceDeployer.ManifestPath, managedAnnotations)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       sequences, err := 
manifestParser.ComposeSequencesFromAllPackages(deployer.serviceDeployer.ClientConfig.Namespace,
 manifest, deployer.serviceDeployer.ManifestPath, managedAnnotations)
+       sequences, err := 
manifestParser.ComposeSequencesFromAllPackages(reader.serviceDeployer.ClientConfig.Namespace,
 manifest, reader.serviceDeployer.ManifestPath, managedAnnotations)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       triggers, err := 
manifestParser.ComposeTriggersFromAllPackages(manifest, 
deployer.serviceDeployer.ManifestPath, managedAnnotations)
+       triggers, err := 
manifestParser.ComposeTriggersFromAllPackages(manifest, 
reader.serviceDeployer.ManifestPath, managedAnnotations)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
@@ -93,37 +93,37 @@ func (deployer *ManifestReader) HandleYaml(sdeployer 
*ServiceDeployer, manifestP
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       apis, err := 
manifestParser.ComposeApiRecordsFromAllPackages(deployer.serviceDeployer.ClientConfig,
 manifest)
+       apis, err := 
manifestParser.ComposeApiRecordsFromAllPackages(reader.serviceDeployer.ClientConfig,
 manifest)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       err = deployer.SetDependencies(deps)
+       err = reader.SetDependencies(deps)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       err = deployer.SetActions(actions)
+       err = reader.SetActions(actions)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       err = deployer.SetSequences(sequences)
+       err = reader.SetSequences(sequences)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       err = deployer.SetTriggers(triggers)
+       err = reader.SetTriggers(triggers)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       err = deployer.SetRules(rules)
+       err = reader.SetRules(rules)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
 
-       err = deployer.SetApis(apis)
+       err = reader.SetApis(apis)
        if err != nil {
                return wskderrors.NewYAMLFileFormatError(manifestName, err)
        }
@@ -131,36 +131,6 @@ func (deployer *ManifestReader) HandleYaml(sdeployer 
*ServiceDeployer, manifestP
        return nil
 }
 
-func (reader *ManifestReader) SetDependencies(deps 
map[string]utils.DependencyRecord) error {
-       for name, dep := range deps {
-               n := strings.Split(name, ":")
-               depName := n[1]
-               if depName == "" {
-                       return nil
-               }
-               if !dep.IsBinding && !reader.IsUndeploy {
-                       if _, exists := 
reader.serviceDeployer.DependencyMaster[depName]; !exists {
-                               // dependency
-                               gitReader := utils.NewGitReader(depName, dep)
-                               err := gitReader.CloneDependency()
-                               if err != nil {
-                                       return 
wskderrors.NewYAMLFileFormatError(depName, err)
-                               }
-                       } else {
-                               // TODO: we should do a check to make sure this 
dependency is compatible with an already installed one.
-                               // If not, we should throw dependency mismatch 
error.
-                       }
-               }
-
-               // store in two places (one local to package to preserve 
relationship, one in master record to check for conflics
-               
reader.serviceDeployer.Deployment.Packages[dep.Packagename].Dependencies[depName]
 = dep
-               reader.serviceDeployer.DependencyMaster[depName] = dep
-
-       }
-
-       return nil
-}
-
 func (reader *ManifestReader) SetPackages(packages map[string]*whisk.Package) 
error {
 
        dep := reader.serviceDeployer
@@ -169,13 +139,6 @@ func (reader *ManifestReader) SetPackages(packages 
map[string]*whisk.Package) er
        defer dep.mt.Unlock()
 
        for _, pkg := range packages {
-               _, exist := dep.Deployment.Packages[pkg.Name]
-               if exist {
-                       // TODO(): i18n of error message (or create a new named 
error)
-                       // TODO(): Is there a better way to handle an existing 
dependency of same name?
-                       err := errors.New("Package [" + pkg.Name + "] exists 
already.")
-                       return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
-               }
                newPack := NewDeploymentPackage()
                newPack.Package = pkg
                dep.Deployment.Packages[pkg.Name] = newPack
@@ -183,126 +146,78 @@ func (reader *ManifestReader) SetPackages(packages 
map[string]*whisk.Package) er
        return nil
 }
 
-func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error {
+func (reader *ManifestReader) SetDependencies(deps 
map[string]utils.DependencyRecord) error {
 
        dep := reader.serviceDeployer
 
        dep.mt.Lock()
        defer dep.mt.Unlock()
 
-       for _, manifestAction := range actions {
-               existAction, exists := 
reader.serviceDeployer.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name]
-
-               if exists == true {
-                       if existAction.Filepath == manifestAction.Filepath || 
manifestAction.Filepath == "" {
-                               // we're adding a filesystem detected action so 
just updated code and filepath if needed
-                               if manifestAction.Action.Exec.Kind != "" {
-                                       existAction.Action.Exec.Kind = 
manifestAction.Action.Exec.Kind
-                               }
-
-                               if manifestAction.Action.Exec.Code != nil {
-                                       code := *manifestAction.Action.Exec.Code
-                                       if code != "" {
-                                               existAction.Action.Exec.Code = 
manifestAction.Action.Exec.Code
-                                       }
-                               }
-
-                               existAction.Action.Annotations = 
manifestAction.Action.Annotations
-                               existAction.Action.Limits = 
manifestAction.Action.Limits
-                               existAction.Action.Parameters = 
manifestAction.Action.Parameters
-                               existAction.Action.Version = 
manifestAction.Action.Version
-
-                               if manifestAction.Filepath != "" {
-                                       existAction.Filepath = 
manifestAction.Filepath
-                               }
-
-                               err := reader.checkAction(existAction)
-                               if err != nil {
-                                       return 
wskderrors.NewFileReadError(manifestAction.Filepath, err)
+       for name, dependency := range deps {
+               // name is <packagename>:<dependencylabel>
+               depName := strings.Split(name, ":")[1]
+               if len(depName) == 0 {
+                       return nil
+               }
+               if !dependency.IsBinding && !reader.IsUndeploy {
+                       if _, exists := dep.DependencyMaster[depName]; exists {
+                               if 
!utils.CompareDependencyRecords(dep.DependencyMaster[depName], dependency) {
+                                       location := 
strings.Join([]string{dep.DependencyMaster[depName].Location, 
dependency.Location}, ",")
+                                       errmsg := 
wski18n.T(wski18n.ID_ERR_DEPENDENCIES_WITH_SAME_LABEL_X_dependency_X_location_X,
+                                               
map[string]interface{}{wski18n.KEY_DEPENDENCY: depName,
+                                                       wski18n.KEY_LOCATION: 
location})
+                                       return 
wskderrors.NewYAMLParserErr(dep.ManifestPath, errmsg)
                                }
-
-                       } else {
-                               // Action exists, but references two different 
sources
-                               // TODO(): i18n of error message (or create a 
new named error)
-                               err := errors.New("Conflict detected for action 
named [" +
-                                       existAction.Action.Name + "].\nFound 
two locations for source file: [" +
-                                       existAction.Filepath + "] and [" + 
manifestAction.Filepath + "]")
-                               return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
                        }
-               } else {
-                       // not a new action so update the action in the package
-                       err := reader.checkAction(manifestAction)
+                       gitReader := utils.NewGitReader(depName, dependency)
+                       err := gitReader.CloneDependency()
                        if err != nil {
-                               return 
wskderrors.NewFileReadError(manifestAction.Filepath, err)
+                               return err
                        }
-                       
reader.serviceDeployer.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name]
 = manifestAction
                }
+               // store in two places (one local to package to preserve 
relationship, one in master record to check for conflics
+               
dep.Deployment.Packages[dependency.Packagename].Dependencies[depName] = 
dependency
+               dep.DependencyMaster[depName] = dependency
        }
 
        return nil
 }
 
-// TODO create named errors
-// Check action record before deploying it
-// action record is created by reading and composing action elements from 
manifest file
-// Action.kind is mandatory which is set to
-// (1) action runtime for an action and (2) set to "sequence" for a sequence
-// Also, action executable code should be specified for any action
-func (reader *ManifestReader) checkAction(action utils.ActionRecord) error {
-       if action.Action.Exec.Kind == "" {
-               // TODO(): i18n of error message (or create a new named error)
-               err := errors.New("Action [" + action.Action.Name + "] has no 
kind set.")
-               return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
-       }
+func (reader *ManifestReader) SetActions(actions []utils.ActionRecord) error {
 
-       if action.Action.Exec.Code != nil {
-               code := *action.Action.Exec.Code
-               if code == "" && action.Action.Exec.Kind != 
parsers.YAML_KEY_SEQUENCE {
-                       // TODO(): i18n of error message (or create a new named 
error)
-                       err := errors.New("Action [" + action.Action.Name + "] 
has no source code.")
-                       return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
+       dep := reader.serviceDeployer
+
+       dep.mt.Lock()
+       defer dep.mt.Unlock()
+
+       for _, manifestAction := range actions {
+               err := reader.checkAction(manifestAction)
+               if err != nil {
+                       return err
                }
+               
dep.Deployment.Packages[manifestAction.Packagename].Actions[manifestAction.Action.Name]
 = manifestAction
        }
-
        return nil
 }
 
-func (reader *ManifestReader) SetSequences(actions []utils.ActionRecord) error 
{
+func (reader *ManifestReader) SetSequences(sequences []utils.ActionRecord) 
error {
        dep := reader.serviceDeployer
 
        dep.mt.Lock()
        defer dep.mt.Unlock()
 
-       for _, seqAction := range actions {
-               // check if the sequence action is exist in actions
-               // If the sequence action exists in actions, return error
-               _, exists := 
reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Actions[seqAction.Action.Name]
-               if exists == true {
-                       // TODO(798): i18n of error message (or create a new 
named error)
-                       err := errors.New("Sequence action's name [" +
-                               seqAction.Action.Name + "] is already used by 
an action.")
+       for _, sequence := range sequences {
+               // If the sequence name matches with any of the actions 
defined, return error
+               if _, exists := 
dep.Deployment.Packages[sequence.Packagename].Actions[sequence.Action.Name]; 
exists {
+                       err := 
wski18n.T(wski18n.ID_ERR_SEQUENCE_HAVING_SAME_NAME_AS_ACTION_X_action_X,
+                               map[string]interface{}{wski18n.KEY_SEQUENCE: 
sequence.Action.Name})
                        return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
                }
-               existAction, exists := 
reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Sequences[seqAction.Action.Name]
-
-               if exists == true {
-                       existAction.Action.Annotations = 
seqAction.Action.Annotations
-                       existAction.Action.Exec.Kind = "sequence"
-                       existAction.Action.Exec.Components = 
seqAction.Action.Exec.Components
-                       existAction.Action.Publish = seqAction.Action.Publish
-                       existAction.Action.Namespace = 
seqAction.Action.Namespace
-                       existAction.Action.Limits = seqAction.Action.Limits
-                       existAction.Action.Parameters = 
seqAction.Action.Parameters
-                       existAction.Action.Version = seqAction.Action.Version
-               } else {
-                       // not a new action so update the action in the package
-                       err := reader.checkAction(seqAction)
-                       if err != nil {
-                               // TODO() Need a better error type here
-                               return 
wskderrors.NewFileReadError(seqAction.Filepath, err)
-                       }
-                       
reader.serviceDeployer.Deployment.Packages[seqAction.Packagename].Sequences[seqAction.Action.Name]
 = seqAction
+               err := reader.checkAction(sequence)
+               if err != nil {
+                       return err
                }
+               
dep.Deployment.Packages[sequence.Packagename].Sequences[sequence.Action.Name] = 
sequence
        }
 
        return nil
@@ -317,19 +232,29 @@ func (reader *ManifestReader) SetTriggers(triggers 
[]*whisk.Trigger) error {
        defer dep.mt.Unlock()
 
        for _, trigger := range triggers {
-               existTrigger, exist := dep.Deployment.Triggers[trigger.Name]
-               if exist {
-                       existTrigger.Name = trigger.Name
-                       existTrigger.ActivationId = trigger.ActivationId
-                       existTrigger.Namespace = trigger.Namespace
-                       existTrigger.Annotations = trigger.Annotations
-                       existTrigger.Version = trigger.Version
-                       existTrigger.Parameters = trigger.Parameters
-                       existTrigger.Publish = trigger.Publish
-               } else {
-                       dep.Deployment.Triggers[trigger.Name] = trigger
+               if _, exists := dep.Deployment.Triggers[trigger.Name]; exists {
+                       var feed string
+                       var existingFeed string
+                       for _, a := range 
dep.Deployment.Triggers[trigger.Name].Annotations {
+                               if a.Key == parsers.YAML_KEY_FEED {
+                                       existingFeed = a.Value.(string)
+                               }
+                       }
+                       for _, a := range trigger.Annotations {
+                               if a.Key == parsers.YAML_KEY_FEED {
+                                       feed = a.Value.(string)
+                               }
+                       }
+                       if feed != existingFeed {
+                               feed = fmt.Sprintf("%q", feed)
+                               existingFeed = fmt.Sprintf("%q", existingFeed)
+                               err := 
wski18n.T(wski18n.ID_ERR_CONFLICTING_TRIGGERS_ACROSS_PACKAGES_X_trigger_X_feed_X,
+                                       
map[string]interface{}{wski18n.KEY_TRIGGER: trigger.Name,
+                                               wski18n.KEY_TRIGGER_FEED: 
strings.Join([]string{feed, existingFeed}, ", ")})
+                               return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
+                       }
                }
-
+               dep.Deployment.Triggers[trigger.Name] = trigger
        }
        return nil
 }
@@ -341,19 +266,24 @@ func (reader *ManifestReader) SetRules(rules 
[]*whisk.Rule) error {
        defer dep.mt.Unlock()
 
        for _, rule := range rules {
-               existRule, exist := dep.Deployment.Rules[rule.Name]
-               if exist {
-                       existRule.Name = rule.Name
-                       existRule.Publish = rule.Publish
-                       existRule.Version = rule.Version
-                       existRule.Namespace = rule.Namespace
-                       existRule.Action = rule.Action
-                       existRule.Trigger = rule.Trigger
-                       existRule.Status = rule.Status
-               } else {
-                       dep.Deployment.Rules[rule.Name] = rule
+               if _, exists := dep.Deployment.Rules[rule.Name]; exists {
+                       action := rule.Action.(string)
+                       existingAction := 
dep.Deployment.Rules[rule.Name].Action.(string)
+                       trigger := rule.Trigger.(string)
+                       existingTrigger := 
dep.Deployment.Rules[rule.Name].Trigger.(string)
+                       if action != existingAction || trigger != 
existingTrigger {
+                               action = fmt.Sprintf("%q", action)
+                               existingAction = fmt.Sprintf("%q", 
existingAction)
+                               trigger = fmt.Sprintf("%q", trigger)
+                               existingTrigger = fmt.Sprintf("%q", 
existingTrigger)
+                               err := 
wski18n.T(wski18n.ID_ERR_CONFLICTING_RULES_ACROSS_PACKAGES_X_rule_X_action_X_trigger_X,
+                                       
map[string]interface{}{wski18n.KEY_RULE: rule.Name,
+                                               wski18n.KEY_TRIGGER: 
strings.Join([]string{trigger, existingTrigger}, ", "),
+                                               wski18n.KEY_ACTION:  
strings.Join([]string{action, existingAction}, ", ")})
+                               return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
+                       }
                }
-
+               dep.Deployment.Rules[rule.Name] = rule
        }
        return nil
 }
@@ -365,13 +295,31 @@ func (reader *ManifestReader) SetApis(ar 
[]*whisk.ApiCreateRequest) error {
        defer dep.mt.Unlock()
 
        for _, api := range ar {
-               existApi, exist := dep.Deployment.Apis[api.ApiDoc.Action.Name]
-               if exist {
-                       existApi.ApiDoc.ApiName = api.ApiDoc.ApiName
-               } else {
-                       dep.Deployment.Apis[api.ApiDoc.Action.Name] = api
-               }
+               dep.Deployment.Apis[api.ApiDoc.Action.Name] = api
+       }
+       return nil
+}
 
+// Check action record before deploying it
+// action record is created by reading and composing action elements from 
manifest file
+// Action.kind is mandatory which is set to
+// (1) action runtime for an action and (2) set to "sequence" for a sequence
+// Also, action executable code should be specified for any action
+func (reader *ManifestReader) checkAction(action utils.ActionRecord) error {
+       if action.Action.Exec.Kind == "" {
+               err := wski18n.T(wski18n.ID_ERR_ACTION_WITHOUT_KIND_X_action_X,
+                       map[string]interface{}{wski18n.KEY_ACTION: 
action.Action.Name})
+               return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
+       }
+
+       if action.Action.Exec.Code != nil {
+               code := *action.Action.Exec.Code
+               if code == "" && action.Action.Exec.Kind != 
parsers.YAML_KEY_SEQUENCE {
+                       err := 
wski18n.T(wski18n.ID_ERR_ACTION_WITHOUT_SOURCE_X_action_X,
+                               map[string]interface{}{wski18n.KEY_ACTION: 
action.Action.Name})
+                       return 
wskderrors.NewYAMLParserErr(reader.serviceDeployer.ManifestPath, err)
+               }
        }
+
        return nil
 }
diff --git a/deployers/manifestreader_test.go b/deployers/manifestreader_test.go
index 7d5acbc..bf2e439 100644
--- a/deployers/manifestreader_test.go
+++ b/deployers/manifestreader_test.go
@@ -20,38 +20,327 @@
 package deployers
 
 import (
+       "fmt"
+       "testing"
+
        "github.com/apache/incubator-openwhisk-client-go/whisk"
        "github.com/apache/incubator-openwhisk-wskdeploy/parsers"
        "github.com/apache/incubator-openwhisk-wskdeploy/utils"
        "github.com/apache/incubator-openwhisk-wskdeploy/wskprint"
        "github.com/stretchr/testify/assert"
-       "testing"
 )
 
 var mr *ManifestReader
 var ps *parsers.YAMLParser
 var ms *parsers.YAML
 
-func init() {
+const (
+       // local error messages
+       TEST_ERROR_BUILD_SERVICE_DEPLOYER        = "Manifest [%s]: Failed to 
build service deployer."
+       TEST_ERROR_MANIFEST_PARSE_FAILURE        = "Manifest [%s]: Failed to 
parse."
+       TEST_ERROR_MANIFEST_SET_PACKAGES         = "Manifest [%s]: Failed to 
set packages."
+       TEST_ERROR_FAILED_TO_REPORT_ERROR        = "Manifest [%s]: Failed to 
report parser error."
+       TEST_ERROR_MANIFEST_SET_ANNOTATION       = "[%s]: Failed to set 
Annotation value."
+       TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER  = "[%s]: Failed to set input 
Parameter value."
+       TEST_ERROR_MANIFEST_SET_PUBLISH          = "Package [%s]: Failed to set 
publish."
+       TEST_ERROR_MANIFEST_SET_DEPENDENCIES     = "Package [%s]: Failed to set 
dependencies."
+       TEST_ERROR_MANIFEST_SET_ACTION_CODE      = "Action [%s]: Failed to set 
action code."
+       TEST_ERROR_MANIFEST_SET_ACTION_KIND      = "Action [%s]: Failed to set 
action kind."
+       TEST_ERROR_MANIFEST_SET_ACTION_WEB       = "Action [%s]: Failed to set 
web action."
+       TEST_ERROR_MANIFEST_SET_ACTION_CONDUCTOR = "Action [%s]: Failed to set 
conductor action."
+       TEST_ERROR_MANIFEST_SET_ACTION_IMAGE     = "Action [%s]: Failed to set 
action image."
+)
 
+func init() {
        // Setup "trace" flag for unit tests based upon "go test" -v flag
        utils.Flags.Trace = wskprint.DetectGoTestVerbose()
-
-       sd = NewServiceDeployer()
-       sd.ManifestPath = manifest_file
-       mr = NewManifestReader(sd)
-       ps = parsers.NewYAMLParser()
-       ms, _ = ps.ParseManifest(manifest_file)
 }
 
-// Test could parse Manifest file successfully
-func TestManifestReader_ParseManifest(t *testing.T) {
-       _, _, err := mr.ParseManifest()
-       assert.Equal(t, err, nil, "New ManifestReader failed")
+func buildServiceDeployer(manifestFile string) (*ServiceDeployer, error) {
+       deploymentFile := ""
+       var deployer = NewServiceDeployer()
+       deployer.ManifestPath = manifestFile
+       deployer.DeploymentPath = deploymentFile
+       deployer.Preview = utils.Flags.Preview
+
+       deployer.DependencyMaster = make(map[string]utils.DependencyRecord)
+
+       config := whisk.Config{
+               Namespace:        "test",
+               AuthToken:        "user:pass",
+               Host:             "host",
+               ApigwAccessToken: "token",
+       }
+       deployer.ClientConfig = &config
+
+       op, error := utils.ParseOpenWhisk(deployer.ClientConfig.Host)
+       if error == nil {
+               utils.SupportedRunTimes = utils.ConvertToMap(op)
+               utils.DefaultRunTimes = utils.DefaultRuntimes(op)
+               utils.FileExtensionRuntimeKindMap = 
utils.FileExtensionRuntimes(op)
+               utils.FileRuntimeExtensionsMap = utils.FileRuntimeExtensions(op)
+       }
+
+       return deployer, nil
 }
 
-// Test could Init root package successfully.
 func TestManifestReader_InitPackages(t *testing.T) {
-       err := mr.InitPackages(ps, ms, whisk.KeyValue{})
-       assert.Equal(t, err, nil, "Init Root Package failed")
+       manifestFile := 
"../tests/dat/manifest_validate_package_inputs_and_annotations.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+       assert.Equal(t, 3, len(deployer.Deployment.Packages), 
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, manifestFile, ""))
+
+       expectedParametersAndAnnotations := 0
+
+       for packageName, pack := range deployer.Deployment.Packages {
+               switch packageName {
+               case "helloworld1":
+                       expectedParametersAndAnnotations = 0
+                       assert.False(t, *pack.Package.Publish, 
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PUBLISH, packageName))
+               case "helloworld2":
+                       expectedParametersAndAnnotations = 1
+                       for _, param := range pack.Package.Parameters {
+                               switch param.Key {
+                               case "helloworld_input1":
+                                       assert.Equal(t, "value1", param.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName))
+                               }
+                       }
+                       for _, annotation := range pack.Package.Annotations {
+                               switch annotation.Key {
+                               case "helloworld_annotation1":
+                                       assert.Equal(t, "value1", 
annotation.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName))
+                               }
+                       }
+                       assert.False(t, *pack.Package.Publish, 
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PUBLISH, packageName))
+               case "helloworld3":
+                       expectedParametersAndAnnotations = 2
+                       for _, param := range pack.Package.Parameters {
+                               switch param.Key {
+                               case "helloworld_input1":
+                                       assert.Equal(t, "value1", param.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName))
+                               case "helloworld_input2":
+                                       assert.Equal(t, "value2", param.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, packageName))
+                               }
+                       }
+                       for _, annotation := range pack.Package.Annotations {
+                               switch annotation.Key {
+                               case "helloworld_annotation1":
+                                       assert.Equal(t, "value1", 
annotation.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName))
+                               case "helloworld_annotation2":
+                                       assert.Equal(t, "value2", 
annotation.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, packageName))
+                               }
+                       }
+                       assert.True(t, *pack.Package.Publish, 
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PUBLISH, packageName))
+               }
+               assert.Equal(t, expectedParametersAndAnnotations, 
len(pack.Package.Parameters),
+                       fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, 
packageName))
+               assert.Equal(t, expectedParametersAndAnnotations, 
len(pack.Package.Annotations),
+                       fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, 
packageName))
+       }
+}
+
+func TestManifestReader_SetDependencies(t *testing.T) {
+       manifestFile := "../tests/dat/manifest_validate_dependencies.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+
+       err = manifestReader.HandleYaml(deployer, manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       expectedLocationHelloWorlds := 
"https://github.com/apache/incubator-openwhisk-test/packages/helloworlds";
+       expectedLocationHelloWhisk := 
"https://github.com/apache/incubator-openwhisk-test/packages/hellowhisk";
+       expectedLocationUtils := "/whisk.system/utils"
+
+       for pkgName, pkg := range deployer.Deployment.Packages {
+               switch pkgName {
+               case "helloworld1":
+                       for depName, dep := range pkg.Dependencies {
+                               switch depName {
+                               case "dependency1":
+                               case "helloworlds":
+                                       assert.Equal(t, 
expectedLocationHelloWorlds, dep.Location,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName))
+                               case "dependency2":
+                                       assert.Equal(t, 
expectedLocationHelloWhisk, dep.Location,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName))
+                               case "dependency3":
+                                       assert.Equal(t, expectedLocationUtils, 
dep.Location,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName))
+                               }
+                       }
+
+               case "helloworld2":
+                       for depName, dep := range pkg.Dependencies {
+                               switch depName {
+                               case "helloworlds":
+                               case "dependency1":
+                               case "dependency4":
+                                       assert.Equal(t, 
expectedLocationHelloWorlds, dep.Location,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName))
+                               case "dependency5":
+                                       assert.Equal(t, 
expectedLocationHelloWhisk, dep.Location,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName))
+                               case "dependency6":
+                                       assert.Equal(t, expectedLocationUtils, 
dep.Location,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_DEPENDENCIES, pkgName))
+                               }
+                       }
+               }
+       }
+}
+
+func TestManifestReader_SetDependencies_Bogus(t *testing.T) {
+       manifestFile := "../tests/dat/manifest_validate_dependencies_bogus.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+
+       err = manifestReader.HandleYaml(deployer, manifestParser, manifest, 
whisk.KeyValue{})
+       assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, 
manifestFile))
+}
+
+func TestManifestReader_SetActions(t *testing.T) {
+       manifestFile := "../tests/dat/manifest_validate_action_all.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+
+       err = manifestReader.HandleYaml(deployer, manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       expectedRuntime := "nodejs:6"
+       expectedImage := "openwhisk/skeleton"
+
+       for actionName, action := range 
deployer.Deployment.Packages["helloworld"].Actions {
+               switch actionName {
+               case "helloworld1":
+               case "helloworld2":
+                       assert.NotEmpty(t, action.Action.Exec.Code,
+                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_CODE, actionName))
+                       assert.Equal(t, expectedRuntime, 
action.Action.Exec.Kind,
+                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_KIND, actionName))
+               case "helloworld3":
+                       for _, param := range action.Action.Parameters {
+                               switch param.Key {
+                               case "parameter1":
+                                       assert.Equal(t, "value1", param.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, actionName))
+                               case "parameter2":
+                                       assert.Equal(t, "value2", param.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_INPUT_PARAMETER, actionName))
+                               }
+                       }
+                       for _, annotation := range action.Action.Annotations {
+                               switch annotation.Key {
+                               case "annotation1":
+                                       assert.Equal(t, "value1", 
annotation.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, actionName))
+                               case "annotation2":
+                                       assert.Equal(t, "value2", 
annotation.Value,
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ANNOTATION, actionName))
+                               }
+                       }
+               case "helloworld4":
+                       assert.True(t, action.Action.WebAction(),
+                               fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_WEB, 
actionName))
+               case "helloworld5":
+                       for _, annotation := range action.Action.Annotations {
+                               switch annotation.Key {
+                               case "conductor":
+                                       assert.True(t, annotation.Value.(bool),
+                                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_CONDUCTOR, actionName))
+                               }
+                       }
+               case "helloworld6":
+                       assert.Equal(t, expectedImage, action.Action.Exec.Image,
+                               
fmt.Sprintf(TEST_ERROR_MANIFEST_SET_ACTION_IMAGE, actionName))
+               }
+       }
+}
+
+func TestManifestReader_SetSequences_Bogus(t *testing.T) {
+       manifestFile := "../tests/dat/manifest_validate_sequences_bogus.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+
+       err = manifestReader.HandleYaml(deployer, manifestParser, manifest, 
whisk.KeyValue{})
+       assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, 
manifestFile))
+}
+
+func TestManifestReader_SetTriggers_Bogus(t *testing.T) {
+       manifestFile := "../tests/dat/manifest_validate_triggers_bogus.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+
+       err = manifestReader.HandleYaml(deployer, manifestParser, manifest, 
whisk.KeyValue{})
+       assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, 
manifestFile))
+}
+
+func TestManifestReader_SetRules_Bogus(t *testing.T) {
+       manifestFile := "../tests/dat/manifest_validate_rules_bogus.yaml"
+       deployer, err := buildServiceDeployer(manifestFile)
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_BUILD_SERVICE_DEPLOYER, 
manifestFile))
+
+       var manifestReader = NewManifestReader(deployer)
+       manifestReader.IsUndeploy = false
+       manifest, manifestParser, err := manifestReader.ParseManifest()
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_PARSE_FAILURE, 
manifestFile))
+
+       err = manifestReader.InitPackages(manifestParser, manifest, 
whisk.KeyValue{})
+       assert.Nil(t, err, fmt.Sprintf(TEST_ERROR_MANIFEST_SET_PACKAGES, 
manifestFile))
+
+       err = manifestReader.HandleYaml(deployer, manifestParser, manifest, 
whisk.KeyValue{})
+       assert.NotNil(t, err, fmt.Sprintf(TEST_ERROR_FAILED_TO_REPORT_ERROR, 
manifestFile))
 }
diff --git a/deployers/servicedeployer.go b/deployers/servicedeployer.go
index e35fe96..d3a9894 100644
--- a/deployers/servicedeployer.go
+++ b/deployers/servicedeployer.go
@@ -1570,8 +1570,6 @@ func (deployer *ServiceDeployer) 
getDependentDeployer(depName string, depRecord
        depServiceDeployer.Client = deployer.Client
        depServiceDeployer.ClientConfig = deployer.ClientConfig
 
-       depServiceDeployer.DependencyMaster = deployer.DependencyMaster
-
        // share the master dependency list
        depServiceDeployer.DependencyMaster = deployer.DependencyMaster
 
diff --git a/parsers/manifest_parser.go b/parsers/manifest_parser.go
index c63e4dd..3403820 100644
--- a/parsers/manifest_parser.go
+++ b/parsers/manifest_parser.go
@@ -20,14 +20,12 @@ package parsers
 import (
        "encoding/base64"
        "errors"
+       "gopkg.in/yaml.v2"
        "io/ioutil"
        "os"
        "path"
-       "strings"
-
-       "gopkg.in/yaml.v2"
-
        "path/filepath"
+       "strings"
 
        "github.com/apache/incubator-openwhisk-client-go/whisk"
        "github.com/apache/incubator-openwhisk-wskdeploy/utils"
diff --git a/tests/dat/manifest_validate_action_all.yaml 
b/tests/dat/manifest_validate_action_all.yaml
new file mode 100644
index 0000000..8faf05f
--- /dev/null
+++ b/tests/dat/manifest_validate_action_all.yaml
@@ -0,0 +1,43 @@
+#
+# 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.
+#
+
+packages:
+    helloworld:
+        actions:
+            helloworld1:
+                function: actions/hello.js
+            helloworld2:
+                code: const main = ({ msg }) => { console.log(msg); return 
{msg}; }
+                runtime: nodejs:6
+            helloworld3:
+                function: actions/hello.js
+                annotations:
+                    annotation1: value1
+                    annotation2: value2
+                inputs:
+                    parameter1: value1
+                    parameter2: value2
+            helloworld4:
+                function: actions/hello.js
+                web: true
+            helloworld5:
+                function: actions/hello.js
+                conductor: true
+            helloworld6:
+                function: actions/hello.js
+                docker: openwhisk/skeleton
+
+
diff --git a/tests/dat/manifest_validate_dependencies.yaml 
b/tests/dat/manifest_validate_dependencies.yaml
new file mode 100644
index 0000000..300cdad
--- /dev/null
+++ b/tests/dat/manifest_validate_dependencies.yaml
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+packages:
+    helloworld1:
+        dependencies:
+            helloworlds:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency1:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency2:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/hellowhisk
+            dependency3:
+                location: /whisk.system/utils
+    helloworld2:
+        dependencies:
+            helloworlds:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency1:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency4:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency5:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/hellowhisk
+            dependency6:
+                location: /whisk.system/utils
+
+
+
diff --git a/tests/dat/manifest_validate_dependencies_bogus.yaml 
b/tests/dat/manifest_validate_dependencies_bogus.yaml
new file mode 100644
index 0000000..f75c3b1
--- /dev/null
+++ b/tests/dat/manifest_validate_dependencies_bogus.yaml
@@ -0,0 +1,42 @@
+#
+# 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.
+#
+
+packages:
+    helloworld1:
+        dependencies:
+            helloworlds:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency1:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency2:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/hellowhisk
+            dependency3:
+                location: /whisk.system/utils
+    helloworld2:
+        dependencies:
+            helloworlds:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency1:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/hellowhisk
+            dependency4:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/helloworlds
+            dependency5:
+                location: 
github.com/apache/incubator-openwhisk-test/packages/hellowhisk
+            dependency6:
+                location: /whisk.system/utils
+
+
+
diff --git a/tests/dat/manifest_validate_package_inputs_and_annotations.yaml 
b/tests/dat/manifest_validate_package_inputs_and_annotations.yaml
new file mode 100644
index 0000000..ea5f253
--- /dev/null
+++ b/tests/dat/manifest_validate_package_inputs_and_annotations.yaml
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+
+packages:
+    helloworld1:
+        license: Apache-2.0
+    helloworld2:
+        version: 2.0.0
+        license: MIT
+        inputs:
+            helloworld_input1: value1
+        annotations:
+            helloworld_annotation1: value1
+    helloworld3:
+        version: 3.0.0
+        license: GPL-3.0
+        inputs:
+            helloworld_input1: value1
+            helloworld_input2: value2
+        annotations:
+            helloworld_annotation1: value1
+            helloworld_annotation2: value2
+        public: true
+
diff --git a/tests/dat/manifest_validate_rules_bogus.yaml 
b/tests/dat/manifest_validate_rules_bogus.yaml
new file mode 100644
index 0000000..587929f
--- /dev/null
+++ b/tests/dat/manifest_validate_rules_bogus.yaml
@@ -0,0 +1,41 @@
+#
+# 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.
+#
+
+packages:
+    helloworld1:
+        actions:
+            hello:
+                function: actions/hello.js
+        triggers:
+            trigger1:
+        rules:
+            rule1:
+                trigger: trigger1
+                action: hello
+    helloworld2:
+        actions:
+            hello:
+                function: actions/hello.js
+        triggers:
+            trigger2:
+        rules:
+            rule1:
+                trigger: trigger2
+                action: hello
+            rule2:
+                trigger: trigger2
+                action: hello
+
diff --git a/tests/dat/manifest_validate_sequences_bogus.yaml 
b/tests/dat/manifest_validate_sequences_bogus.yaml
new file mode 100644
index 0000000..4d5425d
--- /dev/null
+++ b/tests/dat/manifest_validate_sequences_bogus.yaml
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+
+packages:
+    helloworld:
+        actions:
+            hello:
+                function: actions/hello.js
+                runtime: nodejs:6
+            helloWithParams:
+                function: actions/hello.js
+                runtime: nodejs:6
+                inputs:
+                    name: Amy
+                    place: Paris
+            helloWithParams1:
+                function: actions/hello.js
+                runtime: nodejs:6
+                inputs:
+                    name: Amy
+                    place: Paris
+        sequences:
+            hello:
+                actions: helloWithParams, helloWithParams1
+
diff --git a/tests/dat/manifest_validate_triggers_bogus.yaml 
b/tests/dat/manifest_validate_triggers_bogus.yaml
new file mode 100644
index 0000000..2b3b2c2
--- /dev/null
+++ b/tests/dat/manifest_validate_triggers_bogus.yaml
@@ -0,0 +1,33 @@
+#
+# 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.
+#
+
+packages:
+    helloworld1:
+        actions:
+            hello:
+                function: actions/hello.js
+        triggers:
+            trigger1:
+            trigger2:
+    helloworld2:
+        actions:
+            hello:
+                function: actions/hello.js
+        triggers:
+            trigger1:
+            trigger2:
+                feed: /whisk.system/alarms/alarm
+
diff --git a/utils/dependencies.go b/utils/dependencies.go
index 9f1dd08..eba29b8 100644
--- a/utils/dependencies.go
+++ b/utils/dependencies.go
@@ -88,3 +88,13 @@ func LocationIsGithub(location string) bool {
        paths := strings.SplitN(removeProtocol(location), "/", 2)
        return strings.Contains(paths[0], GITHUB)
 }
+
+func CompareDependencyRecords(d1 DependencyRecord, d2 DependencyRecord) bool {
+       if (d1.Location == d2.Location) && (d1.Version == d2.Version) {
+               return true
+       }
+       if (d1.BaseRepo == d2.BaseRepo) && (d1.SubFolder == d2.SubFolder) && 
(d1.Version == d2.Version) {
+               return true
+       }
+       return false
+}
diff --git a/utils/gitreader.go b/utils/gitreader.go
index 9d9c84b..741da88 100644
--- a/utils/gitreader.go
+++ b/utils/gitreader.go
@@ -129,6 +129,5 @@ func (reader *GitReader) CloneDependency() error {
        }
 
        os.Rename(rootDir, depPath)
-
        return nil
 }
diff --git a/wski18n/i18n_ids.go b/wski18n/i18n_ids.go
index eae4a0b..9807f0d 100644
--- a/wski18n/i18n_ids.go
+++ b/wski18n/i18n_ids.go
@@ -78,6 +78,9 @@ const (
        KEY_DEPENDENCY      = "dependency"
        KEY_LOCATION        = "location"
        KEY_SEQUENCE        = "sequence"
+       KEY_TRIGGER         = "trigger"
+       KEY_TRIGGER_FEED    = "feed"
+       KEY_RULE            = "rule"
 )
 
 // DO NOT TRANSLATE
@@ -163,25 +166,31 @@ const (
        ID_MSG_MANAGED_FOUND_DELETED_X_key_X_name_X_project_X = 
"msg_managed_found_deleted_entity"
 
        // Errors
-       ID_ERR_DEPENDENCY_UNKNOWN_TYPE                                     = 
"msg_err_dependency_unknown_type"
-       ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X                          = 
"msg_err_entity_create"
-       ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X                          = 
"msg_err_entity_delete"
-       ID_ERR_FEED_INVOKE_X_err_X_code_X                                  = 
"msg_err_feed_invoke"
-       ID_ERR_KEY_MISSING_X_key_X                                         = 
"msg_err_key_missing_mandatory"
-       ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X                            = 
"msg_err_manifest_not_found"
-       ID_ERR_NAME_MISMATCH_X_key_X_dname_X_dpath_X_mname_X_moath_X       = 
"msg_err_name_mismatch"
-       ID_ERR_RUNTIME_INVALID_X_runtime_X_action_X                        = 
"msg_err_runtime_invalid"
-       ID_ERR_RUNTIME_MISMATCH_X_runtime_X_ext_X_action_X                 = 
"msg_err_runtime_mismatch"
-       ID_ERR_RUNTIMES_GET_X_err_X                                        = 
"msg_err_runtimes_get"
-       ID_ERR_RUNTIME_ACTION_SOURCE_NOT_SUPPORTED_X_ext_X_action_X        = 
"msg_err_runtime_action_source_not_supported"
-       ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X                    = 
"msg_err_url_invalid"
-       ID_ERR_URL_MALFORMED_X_urltype_X_url_X                             = 
"msg_err_url_malformed"
-       ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X = 
"msg_err_api_missing_action_or_sequence"
-       ID_ERR_ACTION_INVALID_X_action_X                                   = 
"msg_err_action_invalid"
-       ID_ERR_ACTION_MISSING_RUNTIME_WITH_CODE_X_action_X                 = 
"msg_err_action_missing_runtime_with_code"
-       ID_ERR_ACTION_FUNCTION_REMOTE_DIR_NOT_SUPPORTED_X_action_X_url_X   = 
"msg_err_action_function_remote_dir_not_supported"
-       ID_ERR_CANT_SAVE_DOCKER_RUNTIME                                    = 
"msg_err_cant_save_docker"
-       ID_ERR_FILE_ALREADY_EXISTS                                         = 
"msg_err_file_already_exists"
+       ID_ERR_DEPENDENCY_UNKNOWN_TYPE                                       = 
"msg_err_dependency_unknown_type"
+       ID_ERR_ENTITY_CREATE_X_key_X_err_X_code_X                            = 
"msg_err_entity_create"
+       ID_ERR_ENTITY_DELETE_X_key_X_err_X_code_X                            = 
"msg_err_entity_delete"
+       ID_ERR_FEED_INVOKE_X_err_X_code_X                                    = 
"msg_err_feed_invoke"
+       ID_ERR_KEY_MISSING_X_key_X                                           = 
"msg_err_key_missing_mandatory"
+       ID_ERR_MANIFEST_FILE_NOT_FOUND_X_path_X                              = 
"msg_err_manifest_not_found"
+       ID_ERR_NAME_MISMATCH_X_key_X_dname_X_dpath_X_mname_X_moath_X         = 
"msg_err_name_mismatch"
+       ID_ERR_RUNTIME_INVALID_X_runtime_X_action_X                          = 
"msg_err_runtime_invalid"
+       ID_ERR_RUNTIME_MISMATCH_X_runtime_X_ext_X_action_X                   = 
"msg_err_runtime_mismatch"
+       ID_ERR_RUNTIMES_GET_X_err_X                                          = 
"msg_err_runtimes_get"
+       ID_ERR_RUNTIME_ACTION_SOURCE_NOT_SUPPORTED_X_ext_X_action_X          = 
"msg_err_runtime_action_source_not_supported"
+       ID_ERR_URL_INVALID_X_urltype_X_url_X_filetype_X                      = 
"msg_err_url_invalid"
+       ID_ERR_URL_MALFORMED_X_urltype_X_url_X                               = 
"msg_err_url_malformed"
+       ID_ERR_API_MISSING_ACTION_OR_SEQUENCE_X_action_or_sequence_X_api_X   = 
"msg_err_api_missing_action_or_sequence"
+       ID_ERR_ACTION_INVALID_X_action_X                                     = 
"msg_err_action_invalid"
+       ID_ERR_ACTION_MISSING_RUNTIME_WITH_CODE_X_action_X                   = 
"msg_err_action_missing_runtime_with_code"
+       ID_ERR_ACTION_FUNCTION_REMOTE_DIR_NOT_SUPPORTED_X_action_X_url_X     = 
"msg_err_action_function_remote_dir_not_supported"
+       ID_ERR_CANT_SAVE_DOCKER_RUNTIME                                      = 
"msg_err_cant_save_docker"
+       ID_ERR_FILE_ALREADY_EXISTS                                           = 
"msg_err_file_already_exists"
+       ID_ERR_DEPENDENCIES_WITH_SAME_LABEL_X_dependency_X_location_X        = 
"msg_err_different_dependencies_with_same_label"
+       ID_ERR_ACTION_WITHOUT_KIND_X_action_X                                = 
"msg_err_action_without_kind"
+       ID_ERR_ACTION_WITHOUT_SOURCE_X_action_X                              = 
"msg_err_action_without_source"
+       ID_ERR_SEQUENCE_HAVING_SAME_NAME_AS_ACTION_X_action_X                = 
"msg_err_sequence_having_same_name_as_action"
+       ID_ERR_CONFLICTING_TRIGGERS_ACROSS_PACKAGES_X_trigger_X_feed_X       = 
"msg_err_conflicting_triggers_across_packages"
+       ID_ERR_CONFLICTING_RULES_ACROSS_PACKAGES_X_rule_X_action_X_trigger_X = 
"msg_err_conflicting_rules_across_packages"
 
        // Server-side Errors (wskdeploy as an Action)
        ID_ERR_JSON_MISSING_KEY_CMD = "msg_err_json_missing_cmd_key"
diff --git a/wski18n/i18n_resources.go b/wski18n/i18n_resources.go
index e77a8f5..030d962 100755
--- a/wski18n/i18n_resources.go
+++ b/wski18n/i18n_resources.go
@@ -97,7 +97,7 @@ func wski18nResourcesDe_deAllJson() (*asset, error) {
        return a, nil
 }
 
-var _wski18nResourcesEn_usAllJson = 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5b\x6f\x8f\xdb\x36\xd2\x7f\x9f\x4f\x31\x08\x1e\x20\x2d\xe0\x28\x69\x1f\x3c\xc0\x83\x00\x79\x91\x6b\xd2\x76\xaf\x4d\x36\xd8\xcd\x5e\x50\xe4\x16\x0a\x2d\x8d\x6d\xd6\x12\xa9\x23\x29\x3b\xae\xe1\xef\x7e\x98\x21\xf5\xc7\xde\xa5\xa4\x75\xda\xbb\xbe\xa9\xbb\x1c\xce\xfc\x66\x38\x9c\x7f\x54\x3f\x3d\x02\xd8\x3f\x02\x00\x78\x2c\xf3\xc7\x2f\xe0\x71\x69\x97\x69\x65\x70\x21\xbf\xa4\x68\x8c\x36\x8f\x67\x7e\xd5\x19
 [...]
+var _wski18nResourcesEn_usAllJson = 
[]byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x5b\x5f\x8f\xdb\x36\x12\x7f\xcf\xa7\x18\x04\x07\xa4\x05\x1c\x6d\xda\xc3\x01\x87\x00\x79\xc8\x35\x69\x9b\x6b\x93\x0d\x76\x93\x0b\x8a\xdc\x42\xa1\xa5\xb1\xcd\x5a\x22\x75\x24\x65\xc7\x5d\xec\x77\x3f\xcc\x90\x94\x64\xaf\xf5\xc7\x4e\x7a\x97\x97\x68\x97\xe4\xcc\x6f\x86\xc3\xf9\x47\xee\xc7\x07\x00\xb7\x0f\x00\x00\x1e\xca\xfc\xe1\x53\x78\x58\xda\x65\x5a\x19\x5c\xc8\xcf\x29\x1a\xa3\xcd\xc3\x99\x1f\x75\x46\x28
 [...]
 
 func wski18nResourcesEn_usAllJsonBytes() ([]byte, error) {
        return bindataRead(
@@ -112,7 +112,7 @@ func wski18nResourcesEn_usAllJson() (*asset, error) {
                return nil, err
        }
 
-       info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 
14286, mode: os.FileMode(420), modTime: time.Unix(1523039220, 0)}
+       info := bindataFileInfo{name: "wski18n/resources/en_US.all.json", size: 
15831, mode: os.FileMode(420), modTime: time.Unix(1523315322, 0)}
        a := &asset{bytes: bytes, info: info}
        return a, nil
 }
diff --git a/wski18n/resources/en_US.all.json b/wski18n/resources/en_US.all.json
index f765820..5b32270 100644
--- a/wski18n/resources/en_US.all.json
+++ b/wski18n/resources/en_US.all.json
@@ -316,6 +316,30 @@
     "translation": "File already exists."
   },
   {
+    "id": "msg_err_different_dependencies_with_same_label",
+    "translation": "One single dependency [{{.dependency}}] has two different 
locations [{{.location}}]. This kind of specification is not supported. Please 
update the dependency label [{{.dependency}}] in the manifest file to point to 
same location or create two separate labels for two different locations."
+  },
+  {
+    "id": "msg_err_action_without_kind",
+    "translation": "Action [{{.action}}] has no kind set."
+  },
+  {
+    "id": "msg_err_action_without_code",
+    "translation": "Action [{{.action}}] has no source code."
+  },
+  {
+    "id": "msg_err_sequence_having_same_name_as_action",
+    "translation": "Sequence [{{.sequence}}] is already defined as an action 
under the same package. Actions and sequences can not have same name in a 
single package."
+  },
+  {
+    "id": "msg_err_conflicting_triggers_across_packages",
+    "translation": "One single trigger [{{.trigger}}] is defined with multiple 
feeds [{{.feed}}]. Triggers are created directly under the namespace, its not 
possible to have triggers with same name but different feeds. Please update 
trigger names in manifest file."
+  },
+  {
+    "id": "msg_err_conflicting_rules_across_packages",
+    "translation": "One single rule [{{.rule}}] is defined with different 
actions [{{.action}}] and/or triggers [{{.trigger}}]. Rules are created 
directly under the namespace, its not possible to have rules with same name but 
associated with different actions/triggers. Please update rule names in 
manifest file."
+  },
+  {
     "id": "WARNINGS",
     "translation": "================= WARNINGS ==================="
   },

-- 
To stop receiving notification emails like this one, please contact
mrutkow...@apache.org.

Reply via email to