Giter Club home page Giter Club logo

sfcc-ci's Introduction

Salesforce Commerce Cloud CLI

The Salesforce Commerce Cloud CLI is a command line interface (CLI) for Salesforce Commerce Cloud. It can be used to facilitate deployment and continuous integration practices using Salesforce B2C Commerce.

The CLI can be used from any machine either locally or from build tools, like Jenkins, Travis CI, Bitbucket Pipelines, Heroku CI etc.

In addition to the CLI a basic JavaScript API is included which can be used to integrate with higher level applications on Node.js.

License

As of version 2.3.0 this project is released under the BSD-3-Clause license. For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause.

Contributing

To contribute to this project, follow the Contribution Guidelines. All external contributors must sign the Contributor License Agreement (CLA).

How to get further support?

Feel free to create issues and enhancement requests or browse and discuss existing ones at https://github.com/SalesforceCommerceCloud/sfcc-ci/issues, this will help us understanding in which area the biggest need is. Please refer to documentation below before doing so. If you need help, advice, discuss something, start a thread in our community at https://sfcc-unofficial.slack.com/ in channel #sfcc-ci (request an invitation here).

  • Maintainer: @tobiaslohr

What is this repository for?

The focus of the tool is to streamline and easy the communication with Commerce Cloud instances as part of the CI/CD processes. It focuses on the deployment part supporting quality checks such as test execution, not on the quality checks itself.

Features:

  • Interactive and headless authentication against Account Manager
  • Support for B2C On-Demand Developer Sandboxes
  • Uses Open Commerce APIs completely
  • Authentication using Oauth2
  • Configuration of multiple instances incl. aliasing
  • WebDAV connectivity
  • Code deployment and code version management
  • System job execution and monitoring (site import)
  • Custom job execution and monitoring
  • Add cartridges to site cartridge path
  • Exploring Account Manager orgs and management of users and roles
  • JavaScript API

How do I get set up?

Prerequisites

Configure an API key

Ensure you have a valid Commerce Cloud API key (client ID) set up. If you don't have a API key, you can create one using the Account Manager. Management of API keys is done in Account Manager > API Client and requires Account Administrator or API Administrator role.

For automation (e.g. a build server integration) you'll need the API key as well as the API secret for authentication. If you want to use authentication in interactive mode, you have to set Redirect URIs to http://localhost:8080. If you want to manage sandboxes you have to set Default Scopes to roles tenantFilter profile.

SLAS Prerequisites

In order to use your API key with SLAS, please ensure the following are configured for your client:

  1. Has Roles > Commerce Cloud Developer Experience > Sandbox API User with "All Sandboxes" scope.
    Account Manager Client ID
  2. Set Default Scopes to:
mail
roles
tenantFilter
profile
openId
  1. Set "Token Endpoint Auth Method" to client_secret_post
  2. Set "Access Token Format" to JWT

Grant your API key access to your instances

In order to perform CLI commands, you have to permit API calls to the Commerce Cloud instance(s) you wish to integrate with. You do that by modifying the Open Commerce API Settings as well as the WebDAV Client Permissions on the Commerce Cloud instance.

  1. Log into the Business Manager
  2. Navigate to Administration > Site Development > Open Commerce API Settings
  3. Make sure, that you select Data API and Global from the select boxes
  4. Add the permission set for your client ID to the settings.

Use the following snippet as your client's permission set, replace my_client_id with your own client ID. Note, if you already have Open Commerce API Settings configured on your instance, e.g. for other API keys, you have to merge this permission set into the existing list of permission sets for the other clients.

    {
      "_v": "19.5",
      "clients":
      [
        {
          "client_id": "my_client_id",
          "resources":
          [
            {
              "resource_id": "/code_versions",
              "methods": ["get"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            {
              "resource_id": "/code_versions/*",
              "methods": ["patch", "delete"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            {
              "resource_id": "/jobs/*/executions",
              "methods": ["post"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            {
              "resource_id": "/jobs/*/executions/*",
              "methods": ["get"],
              "read_attributes": "(**)",
              "write_attributes": "(**)"
            },
            { 
              "resource_id": "/sites/*/cartridges", 
              "methods": ["post"], 
              "read_attributes": "(**)", 
              "write_attributes": "(**)"
            },
            {
              "resource_id":"/role_search",
              "methods":["post"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/roles/*",
              "methods":["get"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/roles/*/user_search",
              "methods":["post"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/roles/*/users/*",
              "methods":["put","delete"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/user_search",
              "methods":["post"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/users",
              "methods":["get"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            },
            {
              "resource_id":"/users/*",
              "methods":["put","get","patch","delete"],
              "read_attributes":"(**)",
              "write_attributes":"(**)"
            }
          ]
        }
      ]
    }
  1. Navigate to Administration > Organization > WebDAV Client Permissions
  2. Add the permission set for your client ID to the permission settings.

Use the following snippet as your client's permission set, replace my_client_id with your client ID. Note, if you already have WebDAV Client Permissions configured, e.g. for other API keys, you have to merge this permission set into the existing list of permission sets for the other clients.

    {
      "clients":
      [
        {
          "client_id": "my_client_id",
          "permissions":
          [
            {
              "path": "/impex",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/cartridges",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/static",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/catalogs/<your-catalog-id>",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/libraries/<your-library-id>",
              "operations": [
                "read_write"
              ]
            },
            {
              "path": "/dynamic/<your-site-id>",
              "operations": [
                "read_write"
              ]
            }
          ]
        }
      ]
    }

Dependencies

If you plan to integrate with the JavaScript API or if you want to download the sources and use the CLI through Node you need Node.js and npm to be installed. No other dependencies.

Please check this guide on how to define dependency to the right version using a GIT url.

If do not want to use the JavaScript API, but just the CLI you don't need Node.js and npm necessarily. See "Installation Instructions" for details below.

Installation Instructions

You can install the CLI from npm, using a pre-built binary or from source using Node.js.

Install from npm

If you already have Node.js installed, you can install globally using npm or run using npx:

npm install -g sfcc-ci

# Or alternatively, using npx:
npx sfcc-ci

Install Prebuilt Binary

If you are using the CLI but don't want to mess around with Node.js you can simply download the latest binaries for your OS at Releases. The assets with each release contain binaries for MacOS, Linux and Windows.

MacOS

  1. Download the binary for MacOS.

  2. Make the binary executable:

     chmod +x ./sfcc-ci-macos
    
  3. Move the binary in to your PATH:

     sudo mv ./sfcc-ci-macos /usr/local/bin/sfcc-ci
    

Linux

  1. Download the binary for Linux.

  2. Make the binary executable:

     chmod +x ./sfcc-ci-linux
    
  3. Move the binary in to your PATH:

     sudo mv ./sfcc-ci-linux /usr/local/bin/sfcc-ci
    

Windows

  1. Download the binary for Windows.

  2. Add the binary in to your PATH:

     set PATH=%PATH%;C:\path\to\binary
    

You are now ready to use the tool by running the main command sfcc-ci.

Building from Source using Node.js

  • Make sure Node.js and npm are installed.
  • Clone or download the sources.
    • If you choose to clone, it best done through ssh along with an ssh key which you have to create with your Github account.
    • If you choose to download the latest sources, you can do so from Releases, after which you have to unzip the archive.
  • cd into the directory and run npm install. You may choose to install globally, by running npm install -g instead.
  • Check if installation was successful by running sfcc-ci --help. In case you encouter any issues with running sfcc-ci, you may run npm link to create a symbolic link explicitly. The symbolic link enables you to run sfcc-ci from any location on your machine.

Using the Command Line Interface

Commands

Use sfcc-ci --help or just sfcc-ci to get started and see the full list of commands available:

  Usage: cli [options] [command]

  Options:
    -V, --version                                                   output the version number
    -D, --debug                                                     enable verbose output
    --selfsigned                                                    allow connection to hosts using self-signed certificates
    -I, --ignorewarnings                                            ignore any warnings logged to the console
    -h, --help                                                      output usage information

  Commands:
    auth:login [options] [client] [secret]                          Authenticate a present user for interactive use
    auth:logout                                                     End the current sessions and clears the authentication
    client:auth [options] [client] [secret] [user] [user_password]  Authenticate an API client with an optional user for automation use
    client:auth:renew                                               Renews the client authentication. Requires the initial client authentication to be run with the --renew option.
    client:auth:token                                               Return the current authentication token
    client:list [options]                                           Lists a Oauth clients you have access to
    client:create [options]                                         Creates a new Oauth client
    client:update [options]                                         Update an Oauth client
    client:rotate [options]                                         Rotate credentials of an Oauth client
    client:delete [options]                                         Delete an Oauth client
    data:upload [options]                                           Uploads a file onto a Commerce Cloud instance
    sandbox:realm:list [options]                                    List realms eligible to manage sandboxes for
    sandbox:realm:update [options]                                  Update realm settings
    sandbox:list [options]                                          List all available sandboxes
    sandbox:ips [options]                                           List inbound and outbound IP addresses for sandboxes
    sandbox:create [options]                                        Create a new sandbox
    sandbox:get [options]                                           Get detailed information about a sandbox
    sandbox:update [options]                                        Update a sandbox
    sandbox:start [options]                                         Start a sandbox
    sandbox:stop [options]                                          Stop a sandbox
    sandbox:restart [options]                                       Restart a sandbox
    sandbox:reset [options]                                         Reset a sandbox
    sandbox:delete [options]                                        Delete a sandbox
    sandbox:alias:add [options]                                     Registers a hostname alias for a sandbox.
    sandbox:alias:list [options]                                    Lists all hostname aliases, which are registered for the given sandbox.
    sandbox:alias:delete [options]                                  Removes a sandbox alias by its ID
    instance:add [options] <instance> [alias]                       Adds a new Commerce Cloud instance to the list of configured instances
    instance:set <alias_or_host>                                    Sets a Commerce Cloud instance as the default instance
    instance:clear                                                  Clears all configured Commerce Cloud instances
    instance:list [options]                                         List instance and client details currently configured
    instance:upload [options] <archive>                             Uploads an instance import file onto a Commerce Cloud instance
    instance:import [options] <archive>                             Perform a instance import (aka site import) on a Commerce Cloud instance
    instance:export [options]                                       Run an instance export
    code:list [options]                                             List all custom code versions deployed on the Commerce Cloud instance
    code:deploy [options] <archive>                                 Deploys a custom code archive onto a Commerce Cloud instance
    code:activate [options] <version>                               Activate the custom code version on a Commerce Cloud instance
    code:delete [options]                                           Delete a custom code version
    code:manifest:generate [options] <localdirectorypaths>          Generates the manifest file based on the given local directories.
    code:compare [options] <localdirectorypaths>                    Compare the given local directories with the given code version (or the active one if none specified) of the Commerce Cloud instance and provide a diff between the two.
    code:deploy:diff [options] <codeversion> <localdirectorypaths>  Generate a manifest for the given local directories. Compare this manifest with the one within the active code version of the instance. Deploy only the files which have been updated locally comparing to the remote, within a newly created code version.Activate this newly generated code version if required in the options
    job:run [options] <job_id> [job_parameters...]                  Starts a job execution on a Commerce Cloud instance
    job:status [options] <job_id> <job_execution_id>                Get the status of a job execution on a Commerce Cloud instance
    cartridge:add [options] <cartridgename>                         Adds a cartridge-name to the site cartridge path
    org:list [options]                                              List all orgs eligible to manage
    role:list [options]                                             List roles
    role:grant [options]                                            Grant a role to a user
    role:revoke [options]                                           Revoke a role from a user
    user:list [options]                                             List users eligible to manage
    user:create [options]                                           Create a new user
    user:update [options]                                           Update a user
    user:delete [options]                                           Delete a user
    user:reset [options]                                            Reset a user
    slas:tenant:list [options]                                      Lists all tenants that belong to a given organization
    slas:tenant:add [options]                                       Adds a SLAS tenant to a given organization or updates an existing one
    slas:tenant:get [options]                                       Gets a SLAS tenant from a given organization
    slas:tenant:delete [options]                                    Deletes a SLAS tenant from a given organization
    slas:client:add [options]                                       Adds a SLAS client to a given tenant or updates an existing one
    slas:client:get [options]                                       Gets a SLAS client from a given tenant
    slas:client:list [options]                                      Lists all SLAS clients that belong to a given tenant
    slas:client:delete [options]                                    Deletes a SLAS client from a given tenant

    Environment:

      $SFCC_LOGIN_URL                    set login url used for authentication
      $SFCC_OAUTH_LOCAL_PORT             set Oauth local port for authentication flow
      $SFCC_OAUTH_CLIENT_ID              client id used for authentication
      $SFCC_OAUTH_CLIENT_SECRET          client secret used for authentication
      $SFCC_OAUTH_USER_NAME              user name used for authentication
      $SFCC_OAUTH_USER_PASSWORD          user password used for authentication
      $SFCC_SANDBOX_API_HOST             set sandbox API host
      $SFCC_SANDBOX_API_POLLING_TIMEOUT  set timeout for sandbox polling in minutes
      $SFCC_SCAPI_SHORTCODE              the Salesforce Commerce (Headless) API Shortcode
      $SFCC_SCAPI_TENANTID               the Salesforce Commerce (Headless) API TenantId
      $DEBUG                             enable verbose output

    Detailed Help:

      Use sfcc-ci <sub:command> --help to get detailed help and example usage of sub:commands

    Useful Resources:

      Salesforce Commerce Cloud CLI Release Notes: https://sfdc.co/sfcc-cli-releasenotes
      Salesforce Commerce Cloud CLI Readme: https://sfdc.co/sfcc-cli-readme
      Salesforce Commerce Cloud CLI Cheatsheet: https://sfdc.co/sfcc-cli-cheatsheet
      Salesforce Commerce Cloud Account Manager: https://account.demandware.com
      Salesforce Commerce Cloud API Explorer: https://api-explorer.commercecloud.salesforce.com
      Salesforce Commerce Cloud Documentation: https://documentation.b2c.commercecloud.salesforce.com

Use sfcc-ci <sub:command> --help to get detailed help and example usage of a sub:command.

Configuration

The CLI keeps it's own settings. The location of these settings are OS specific. On Linux they are located at $HOME/.config/sfcc-ci-nodejs/, on MacOS they are located at $HOME/Library/Preferences/sfcc-ci-nodejs/.

In addition the CLI can be configured by placing a dw.json file into the current working directory. The dw.json may carry details used run authentication.

{
    "client-id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "client-secret": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "username": "user",
    "password": "password",
    "hostname": "<dev-sandbox>.demandware.net"
}

Environment Variables

The use of environment variables is optional. sfcc-ci respects the following environment variables which you can use to control, how the CLI works:

  • SFCC_LOGIN_URL set login url used for authentication
  • SFCC_OAUTH_LOCAL_PORT set Oauth local port for authentication flow
  • SFCC_OAUTH_CLIENT_ID client id used for authentication
  • SFCC_OAUTH_CLIENT_SECRET client secret used for authentication
  • SFCC_OAUTH_USER_NAME user name used for authentication
  • SFCC_OAUTH_USER_PASSWORD user password used for authentication
  • SFCC_SANDBOX_API_HOST set alternative sandbox API host
  • SFCC_SANDBOX_API_POLLING_TIMEOUT set timeout for sandbox polling in minutes
  • DEBUG enable verbose output

If you only want a single CLI command to write debug messages prepend the command using, e.g. DEBUG=* sfcc-ci <sub:command>.

Parameter Precedence

The parameters are used with the following precedence:

  1. Passing explicit params to the commandline (e.g sfcc-ci client:auth client_id client_secret)
  2. Credentials in a dw.json
  3. Creating an .env file
  4. Setting env vars on your machine

Authentication

Oauth Credentials and Secrets

Depending on how you use sfcc-ci you make use of command sfcc-ci auth:login or sfcc-ci client:auth to authenticate. These commands accept credentials being explicitly passed as arguments to these commands. Use sfcc-ci auth:login --help and sfcc-ci client:auth --help for more info. However, there are alternative ways on how to make credentials available to the CLI for authentication:

  • You can define credentials in a dw.json file. The CLI will attempt to read this file (if present) from the current working directory.
  • Alternatively you can use a set of well-known env vars (if set) which the CLI will use. Namely, these are SFCC_OAUTH_CLIENT_ID (client id), SFCC_OAUTH_CLIENT_SECRET (client secret), SFCC_OAUTH_USER_NAME (user name) and SFCC_OAUTH_USER_PASSWORD (user password).
export SFCC_OAUTH_CLIENT_ID=<client-id>
export SFCC_OAUTH_CLIENT_SECRET=<client-secret>
export SFCC_OAUTH_USER_NAME=<user-name>
export SFCC_OAUTH_USER_PASSWORD=<user-password>
  • Lastly you can make use of a .env file, which holds the credentials in form of NAME=VALUE using the same set of well-known env vars as above. The CLI will attempt to make use of the env vars in this file (if present) from the current working directory. For example:
SFCC_OAUTH_CLIENT_ID=<client-id>
SFCC_OAUTH_CLIENT_SECRET=<client-secret>
SFCC_OAUTH_USER_NAME=<user-name>
SFCC_OAUTH_USER_PASSWORD=<user-password>

Authorization Server

sfcc-ci uses a default authorization server. You can overwrite this authorization server and use an alternative login url using the env var SFCC_LOGIN_URL:

export SFCC_LOGIN_URL=<alternative-authorization-server>

Removing the env var (unset SFCC_LOGIN_URL) will make the CLI use the default authorization server again.

Oauth Local Port

sfcc-ci uses a default Oauth local port for authentication flow via command sfcc-ci auth:login. You can overwrite this port and use an alternative port number (e.g. if the default port is used on your machine and you cannot use is) using the env var SFCC_OAUTH_LOCAL_PORT:

export SFCC_OAUTH_LOCAL_PORT=<alternative-port>

Removing the env var (unset SFCC_OAUTH_LOCAL_PORT) will make the CLI use the default port again.

Authorization

Depending on which activities you want to want to perform, you have to ensure proper permissions have been granted beforehand. The required permissions and how to grant them depends on the commands you want to perform and whether you want to execute commands interactively (with the presence of a user) or implement automations (no user present).

Consult the table below to set permissions depending on the activity desired:

Commands Interactive Use Automation Use
data:* OCAPI Data API Settings OCAPI Data API Settings
sandbox:* Sandbox API User role assigned to user Sandbox API User role assigned to API client
instance:* OCAPI Data API Settings OCAPI Data API Settings
code:* OCAPI Data API Settings OCAPI Data API Settings
job:* OCAPI Data API Settings OCAPI Data API Settings
cartridge:* OCAPI Data API Settings OCAPI Data API Settings
org:* Account Administrator role assigned to user Account Administrator role assigned to API client
role:* Account Administrator role assigned to user or OCAPI Data API Settings Account Administrator role assigned to API client or OCAPI Data API Settings
users:* Account Administrator role assigned to user or OCAPI Data API Settings Account Administrator role assigned to API client or OCAPI Data API Settings

Authorizing a User

Authorizing a user usually requires assigning the required role to the user in Account Manager. Assigning a role to a user in Account Manager, such as the Sandbox API User role, itself requires the Account Administrator role.

Authorizing an API Client

Authorizing an API client requires assigning the required role to the API client in Account Manager or granting permissions to the API client on the B2C Commerce instance via the OCAPI Data API settings. Assigning a role to an API client in Account Manager, such as the Sandbox API User role, itself requires the Account Administrator or API Admin role.

Sandbox API

API Server

sfcc-ci uses a default host for the sandbox API. This is the standard Sandbox API Gateway at admin.dx.commercecloud.salesforce.com. Usually this is fine and you don't need to change this. However, you can overwrite this host and use an alternative host using the env var SFCC_SANDBOX_API_HOST:

export SFCC_SANDBOX_API_HOST=<alternative-sandbox-api-host>

Removing the env var (unset SFCC_SANDBOX_API_HOST) will make the CLI use the default host again.

API Polling Timeout

sfcc-ci allows the creation of a sandbox in sync mode (see sfcc-ci sandbox:create --help for details). By default the polling of the sandbox status lasts for 10 minutes at maximum until the timeout is reached. You can overwrite this timeout and specify another timeout in minutes using the env var SFCC_SANDBOX_API_POLLING_TIMEOUT:

export SFCC_SANDBOX_API_POLLING_TIMEOUT=<alternative-sandbox-api-polling-timeout-in-minutes>

Removing the env var (unset SFCC_SANDBOX_API_POLLING_TIMEOUT) will make the CLI use the default timeout again.

Debugging

You can force sfcc-ci to write debug messages to the console using the env var DEBUG. You can do this for globally by setting the env var, so that any following CLI command will write debug messages:

export DEBUG=*

If you only want a single CLI command to write debug messages use the the -D,--debug flag with any command, e.g. sfcc-ci <sub:command> --debug.

Sorting list

To output objects to a sorted list, add the -S,--sortby option to one of the supported commands. Sort objects by specifying any field.

CLI Examples

The examples below assume you have defined a set of environment variables:

  • an API Key (the client ID)
  • an API Secret (the client secret)

On Linux and MacOS you can set environment variables as follows:

export API_KEY=<my-api-key>
export API_SECRET=<my-api-secret>

On Windows you set them as follows:

set API_KEY=<my-api-key>
set API_SECRET=<my-api-secret>

The remainder of the examples below assume you are on Linux or MacOS. If you are on Windows you access environment variables using %MY_ENV_VAR% instead of $MY_ENV_VAR.

Note: Some CLI commands provide structured output of the operation result as JSON. To process this JSON a tool called jq comes in handy. Installation and documentation of jq is located at https://stedolan.github.io/jq/manual/.

Authentication

In an interactive mode you usually authenticate as follows:

sfcc-ci auth:login $API_KEY

In an automation scenario (where no user is present) authentication is done using API client credentials as follows:

sfcc-ci client:auth $API_KEY $API_SECRET

Logging out (and removing auth tokens from the machine):

sfcc-ci auth:logout

Pushing Code

Pushing code to any SFCC instance and activate it:

sfcc-ci code:deploy <path/to/code_version.zip> -i your-instance.demandware.net
sfcc-ci code:activate <code_version> -i your-instance.demandware.net

Data Import

Running an instance import (aka site import) on any SFCC instance:

sfcc-ci instance:upload <path/to/data.zip> -i your-instance.demandware.net
sfcc-ci instance:import <data.zip> -i your-instance.demandware.net -s

Running the instance import without waiting for the import to finish you omit the --sync,-c flag:

sfcc-ci instance:import <data.zip> -i your-instance.demandware.net

Sandboxes

Provision a new sandbox, outputting the inbound and outbound IP addresses, uploading code and running an instance import:

SANDBOX=`sfcc-ci sandbox:create <a-realm> -s -j`
SANDBOX_HOST=`$SANDBOX | jq '.instance.host' -r`
sfcc-ci sandbox:ips
sfcc-ci code:deploy <path/to/code.zip> -i $SANDBOX_HOST
sfcc-ci instance:upload <path/to/data.zip> -i $SANDBOX_HOST -s
sfcc-ci instance:import <data.zip> -i your-instance.demandware.net

Cartridges

Handles the cartridge path of your Site. Very useful for plugin installation. You can put the cartridge on top or at the bottom of the cartridge path. Or if given an anchor cartridge at the before or after a cartridge.

sfcc-ci cartridge:add <cartridgename> -p [first|last] -S <siteid>
sfcc-ci cartridge:add <cartridgename> -p [before|after] -t [targetcartidge] -S <siteid>

Using the JavaScript API

There is a JavaScript API available, which you can use to program against and integrate the commands into your own project.

Make sfcc-ci available to your project by specifying the dependeny in your package.json first and running and npm install in your package. After that you require the API into your implementation using:

  const sfcc = require('sfcc-ci');

The API is structured into sub modules. You may require sub modules directly, e.g.

  const sfcc_auth = require('sfcc-ci').auth;
  const sfcc_cartridge = require('sfcc-ci').cartridge;
  const sfcc_code = require('sfcc-ci').code;
  const sfcc_instance = require('sfcc-ci').instance;
  const sfcc_job = require('sfcc-ci').job;
  const sfcc_slas = require('sfcc-ci').slas;
  const sfcc_user = require('sfcc-ci').user;
  const sfcc_webdav = require('sfcc-ci').webdav;

The following APIs are available (assuming sfcc refers to require('sfcc-ci')):

  sfcc.auth.auth(client_id, client_secret, callback);
  sfcc.cartridge.add(instance, cartridgename, position, target, siteid, verbose, token, callback);
  sfcc.code.activate(instance, code_version, token, callback);
  sfcc.code.deploy(instance, archive, token, options, callback);
  sfcc.code.list(instance, token, callback);
  sfcc.code.compare(instance, localDirectories, options);
  sfcc.code.diffdeploy(instance, localDirectories, codeVersionName, options, activate);
  sfcc.instance.upload(instance, file, token, options, callback);
  sfcc.instance.import(instance, file_name, token, callback);
  sfcc.job.run(instance, job_id, job_params, token, callback);
  sfcc.job.status(instance, job_id, job_execution_id, token, callback);
  sfcc.manifest.generate(directories, ignorePatterns, targetDirectory, fileName);
  sfcc.slas.tenant.add(tenantId, shortcode, description, merchantName, contact, emailAddress, fileName, token).then(result => ...).catch(err => ...);
  sfcc.slas.tenant.get(tenantId, shortcode, token).then(result => ...).catch(err => ...);
  sfcc.slas.tenant.list(shortcode, token).then(result => ...).catch(err => ...);
  sfcc.slas.tenant.delete(tenantId, shortcode, token).then(result => ...).catch(err => ...);
  sfcc.slas.client.add(tenantId, shortcode, file, clientid, clientname, privateclient, ecomtenant, ecomsite, secret, channels, scopes, redirecturis, callbackuris, token).then(result => ...).catch(err => ...);
  sfcc.slas.client.get(tenantId, shortcode, clientId, token).then(result => ...).catch(err => ...);
  sfcc.slas.client.list(shortcode, tenantId, token).then(result => ...).catch(err => ...);
  sfcc.slas.client.delete(tenantId, shortcode, clientId, token).then(result => ...).catch(err => ...);
  sfcc.user.create(org, user, mail, firstName, lastName, token).then(result => ...).catch(err => ...);
  sfcc.user.list(org, role, login, count, sortBy, token).then(result => ...).catch(err => ...);
  sfcc.user.update(login, changes, token).then(result => ...).catch(err => ...);
  sfcc.user.grant(login, role, scope, token).then(result => ...).catch(err => ...);
  sfcc.user.revoke(login, role, scope, token).then(result => ...).catch(err => ...);
  sfcc.user.delete(login, purge, token).then(result => ...).catch(err => ...);
  sfcc.user.reset(login, token).then(result => ...).catch(err => ...);
  sfcc.user.createLocal(instance, login, user, token).then(result => ...).catch(err => ...);
  sfcc.user.searchLocal(instance, login, query, role, sortBy, count, start, token).then(result => ...).catch(err => ...);
  sfcc.user.updateLocal(instance, login, changes, token).then(result => ...).catch(err => ...);
  sfcc.user.grantLocal(instance, login, role, token).then(result => ...).catch(err => ...);
  sfcc.user.revokeLocal(instance, login, role, token).then(result => ...).catch(err => ...);
  sfcc.user.deleteLocal(instance, login, token).then(result => ...).catch(err => ...);
  sfcc.webdav.upload(instance, path, file, token, options, callback);

Authentication

APIs available in require('sfcc-ci').auth:

auth(client_id, client_secret, callback)

Authenticates a clients and attempts to obtain a new Oauth2 token. Note, that tokens should be reused for subsequent operations. In case of a invalid token you may call this method again to obtain a new token.

Param Type Description
client_id (String) The client ID
client_secret (String) The client secret
callback (Function) Callback function executed as a result. The error and the token will be passed as parameters to the callback function.

Returns: (void) Function has no return value

Example:

const sfcc = require('sfcc-ci');

var client_id = 'my_client_id';
var client_secret = 'my_client_id';

sfcc.auth.auth(client_id, client_secret, function(err, token) {
    if(token) {
        console.log('Authentication succeeded. Token is %s', token);
    }
    if(err) {
        console.error('Authentication error: %s', err);
    }
});

Cartridge

APIs available in require('sfcc-ci').cartridge:

add(instance, cartridgename, position, target, siteid, verbose, token, callback)

Allows to add a cartridge to the cartridge path for a given site at a specific position.

Param Type Description
instance (String) The instance to add the cartridge.
cartridgename (String) The given cartride name.
position (String) Either first, last, before or after.
target (String) When position is 'before' or 'after', need to specify the target cartridge.
siteid (String) ID of the site, where the cartrdige should be added.
token (String) The Oauth token to use for authentication.
verbose (Boolean) Wether or not to use logging capabilities.
callback (Function) Callback function executed as a result. The error and the token will be passed as parameters to the callback function.

Returns: (void) Function has no return value

Example:

const sfcc = require('sfcc-ci');

var instance = '"*.sandbox.us01.dx.commercecloud.salesforce.com';
var cartridgename = 'app_custom';
var position = 'before';
var target = 'app_storefront_base';
var siteid = 'RefArch';
var verbose = false;
var token = 1234;

sfcc.cartridge.add(instance, cartridgename, position, target, siteid, verbose, token, function(err, token) {
  // ...
});

Code

APIs available in require('sfcc-ci').code:

deploy(instance, archive, token, options, callback)

Deploys a custom code archive onto a Commerce Cloud instance

Param Type Description
instance (String) The instance to activate the code on
archive (String) The ZIP archive filename to deploy
token (String) The Oauth token to use use for authentication
options (Object) The options parameter can contains two properties: pfx: the path to the client certificate to use for two factor authentication. passphrase: the optional passphrase to use with the client certificate
callback (Function) Callback function executed as a result. The error will be passed as parameter to the callback function.

Returns: (void) Function has no return value


list(instance, token, callback)

Get all custom code versions deployed on a Commerce Cloud instance.

Param Type Description
instance (String) The instance to activate the code on
token (String) The Oauth token to use for authentication
callback (Function) Callback function executed as a result. The error and the code versions will be passed as parameters to the callback function.

Returns: (void) Function has no return value


activate(instance, code_version, token, callback)

Activate the custom code version on a Commerce Cloud instance. If the code version is already active, no error is available.

Param Type Description
instance (String) The instance to activate the code on
code_version (String) The code version to activate
token (String) The Oauth token to use use for authentication
callback (Function) Callback function executed as a result. The error will be passed as parameter to the callback function.

Returns: (void) Function has no return value


compare(instance, localDirectories, options)

Compare the given local directories with the given code version (or the active one if none specified) of the Commerce Cloud instance and provide a diff between the two

Param Type Description
instance (String) The instance to activate the code on
localDirectories (Array) The list of local directories to compare with the remote instance
options (Object) The object that contain all the possible options.
options.sourceCodeVersion (String) This is the name of the code version from the instance to use as source of comparison. If not specified, the active code version is used.
options.manifestFileName (String) The name of the remote manifest file. If not provided, the manifest.FILENAME constant is used.
options.pfx (String) The path to the certificate to authenticate to the instance.
options.passphrase (String) The passphrase associated with the given certificate.
options.overrideLocalFile (Boolean) If not provided, the process won't override any existing manifest previously downloaded, and will abort the process. If provided, then any existing downloaded manifest file will be overridden
options.ignorePatterns (Array) A list of glob patterns to use to ignore files while listing local files and generating the local manifest. If not provided, the default patterns are used: ['test/**/*', 'coverage/**/*', 'documentation/**/*', 'docs/**/*', '*.md']
options.outputFile (Boolean) If provided, a file will be generated with the resuts in the comparison in the process.cwd() folder. Its path is then passed in the resolve method of the returned promise. If not provided, then the comparison results are passed in the resolve method of the returned promise.
options.removeFilesAfter (Boolean) If provided, the downloaded manifest and generated one (for local files) are removed. Only the output file will remain (if the option outputFile is provided). If not provided, any manifest used for the comparison will remain in the process.cwd() folder.
options.verbose (Object) Asks the process to log each stage of the comparison task.

Returns: (Promise) Returns a Promise. The resolve method is called with either:

  • The path of the output file which contain the comparison results, if the outputFile option is passed
  • The JSON representation of the comparison results, if the outputFile option is not passed The reject method is called with any error message if an error occurs during the comparison process

Example:

const sfcc = require('sfcc-ci');

const instance = '"*.sandbox.us01.dx.commercecloud.salesforce.com';
const localDirectories = ['path/to/repo1', 'path/to/repo2'];
const options = {
    ignorePatterns: ['test/**/*', 'docs/**/*'],
    outputFile: true,
    removeFilesAfter: true,
    overrideLocalFile: true
};

sfcc.code.compare(instance, localDirectories, options)
    .then(deltaResult => {
        // do something with the delta result, which contains the difference between the local directories and the remote code version
    })
    .catch(err => console.log(err));

diffdeploy(instance, localDirectories, codeVersionName, options, activate)

Generate a manifest for the given local directories. Compare this manifest with the one within the active code version of the instance. Deploy only the files which have been updated locally comparing to the remote, within a newly created code version. Activate this newly generated code version if required in the options

Param Type Description
instance (String) The instance to activate the code on
localDirectories (Array) The list of local directories to compare with the remote instance
codeVersionName (String) The name of the new code version to use for the newly deployed code version
options (Object) The object that contain all the possible options.
options.sourceCodeVersion (String) This is the name of the code version from the instance to use as source of comparison. If not specified, the active code version is used.
options.manifestFileName (String) The name of the remote manifest file. If not provided, the manifest.FILENAME constant is used.
options.pfx (String) The path to the certificate to authenticate to the instance.
options.passphrase (String) The passphrase associated with the given certificate.
options.overrideLocalFile (Boolean) If not provided, the process won't override any existing manifest previously downloaded, and will abort the process. If provided, then any existing downloaded manifest file will be overridden
options.ignorePatterns (Array ) A list of glob patterns to use to ignore files while listing local files and generating the local manifest. If not provided, the default patterns are used: ['test/**/*', 'coverage/**/*', 'documentation/**/*', 'docs/**/*', '*.md']
options.forceDeployPatterns (Array ) A list of glob patterns to use to force the deployment for those files. The deploy will ALWAYS include these files within the deployment, regardless if these files were not changed or were ignored by the previous ignore patterns list.
options.removeFilesAfter (Boolean) If provided, the downloaded manifest and generated one (for local files) are removed. Only the output file will remain (if the option outputFile is provided). If not provided, any manifest used for the comparison will remain in the process.cwd() folder.
options.verbose (Object) Asks the process to log each stage of the comparison task.
activate (Boolean) Asks the process to activate the newly deployed code version. If not provided, then the code version will remain on the instance deactivated.

Returns: (Promise) Returns a Promise. The resolve method is called with undefined as parameter, meaning that the process finished successfully The reject method is called with any error message if an error occurs during the comparison process

Example:

const sfcc = require('sfcc-ci');

const instance = '"*.sandbox.us01.dx.commercecloud.salesforce.com';
const localDirectories = ['path/to/repo1', 'path/to/repo2'];
const codeVersionName = 'new_code_version';
const activate = true;
const options = {
    sourceCodeVersion: 'code_version_to_use_as_source',
    ignorePatterns: ['test/**/*', 'docs/**/*'],
    forceDeployPatterns: ['**/config/**/*'],
    outputFile: true,
    removeFilesAfter: true,
    overrideLocalFile: true
};

sfcc.code.diffdeploy(instance, localDirectories, codeVersionName, options, activate)
    .then(() => {
        // do something, now that the code has been deployed and activated successfully
    })
    .catch(err => console.log(err));

Instance

APIs available in require('sfcc').instance:

upload(instance, file, token, options, callback)

Uploads an instance import file onto a Commerce Cloud instance.

Param Type Description
instance (String) The instance to upload the import file to
file (String) The file to upload
token (String) The Oauth token to use use for authentication
options (Object) The options parameter can contains two properties: pfx: the path to the client certificate to use for two factor authentication. passphrase: the optional passphrase to use with the client certificate
callback (Function) Callback function executed as a result. The error will be passed as parameter to the callback function.

Returns: (void) Function has no return value


import(instance, file_name, token, callback)

Perform an instance import (aka site import) on a Commerce Cloud instance. You may use the API job.status to get the execution status of the import.

Param Type Description
instance (String) Instance to start the import on
file_name (String) The import file to run the import with
token (String) The Oauth token to use use for authentication
callback (Function) Callback function executed as a result. The error and the job execution details will be passed as parameters to the callback function.

Returns: (void) Function has no return value


Jobs

APIs available in require('sfcc').job:

run(instance, job_id, job_params, token, callback)

Starts a job execution on a Commerce Cloud instance. The job is triggered and the result of the attempt to start the job is returned. You may use the API job.status to get the current job execution status.

Param Type Description
instance (String) Instance to start the job on
job_id (String) The job to start
token (String) The Oauth token to use use for authentication
job_params (Array) Array containing job parameters. A job parameter must be denoted by an object holding a key and a value property.
callback (Function) Callback function executed as a result. The error and the job execution details will be passed as parameters to the callback function.

Returns: (void) Function has no return value


status(instance, job_id, job_execution_id, token, callback)

Get the status of a job execution on a Commerce Cloud instance.

Param Type Description
instance (String) Instance the job was executed on.
job_id (String) The job to get the execution status for
job_execution_id (String) The job execution id to get the status for
token (String) The Oauth token to use use for authentication
callback (Function) Callback function executed as a result. The error and the job execution details will be passed as parameters to the callback function.

Returns: (void) Function has no return value


SLAS

APIs available in require('sfcc').slas:

tenant.add(tenantId, shortcode, description, merchantName, contact, emailAddress, fileName)

Adds the tenant details to the SLAS organization

Param Type Description
tenantId (String) The tenant ID
shortcode (String) The short code of the org
description (String) Description of the tenant
merchantName (String) Name of the merchant
contact (String) Username of the user
emailAddress (String) Email address of the user
fileName (String) Path of the file containing all the params required for the tenant creation.

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the newly created tenant reponse.


tenant.get(tenantId, shortcode)

Gets the tenant matching the given tenantId for the given shortCode

Param Type Description
tenantId (String) The tenant ID
shortcode (String) The short code of the org

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the tenant reponse.


tenant.list(shortcode)

Lists all the tenants for the given shortCode

Param Type Description
shortcode (String) The short code of the org

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is list of tenants reponse.


tenant.delete(tenantId, shortcode)

Deletes the tenant matching the given tenantId for the given shortCode

Param Type Description
tenantId (String) The tenant ID
shortcode (String) The short code of the org

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the deletion reponse.


client.add(tenantId, shortcode, file, clientid, clientname, privateclient, ecomtenant, ecomsite, secret, channels, scopes, redirecturis)

Registers a new client within a given tenant

Param Type Description
tenantId (String) The tenant ID
shortcode (String) The short code of the org
file (String) Path of the file containing all the params required for the client creation.
clientid (String) SLAS client id
clientname (String) The client name
privateclient (Boolean) Is the client a private client or not
ecomtenant (String) The ecom tenant
ecomsite (String) The ecom site
secret (String) The secret tied to the client ID
channels (Array) The list of channels for the client
scopes (Array) The list of scopes authorized for the client
redirecturis (Array) The list of redirect URIs authorized for the client

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the newly created client reponse.


client.get(tenantId, shortcode, clientId)

Gets the tenant matching the given clientid for the given tenantId and shortCode

Param Type Description
tenantId (String) The tenant ID
shortcode (String) The short code of the org
clientid (String) SLAS client id

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the client reponse.


client.list(shortcode, tenantId)

Lists all the clients for the given tenantId and shortCode

Param Type Description
shortcode (String) The short code of the org
tenantId (String) The tenant ID

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is list of clients reponse.


client.delete(tenantId, shortcode, clientId)

Deletes the client matching the given clientId for the given tenantId and shortCode

Param Type Description
tenantId (String) The tenant ID
shortcode (String) The short code of the org
clientid (String) SLAS client id

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the deletion reponse.


User

APIs available in require('sfcc').user:

create(org, user, mail, firstName, lastName, token)

Creates a new user into Account Manager

Param Type Description
org (String) The org ID where to create the user
user (Object) The user object with all the required data in it
mail (String) The email of the user
firstName (String) The firstname of the user
lastName (String) The lastname of the user
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the newly created user object.


list(org, role, login, count, sortBy, token)

Lists all users eligible to manage from the Account Manager, based on the given filters (if any provided)

Param Type Description
org (String) The org ID or null, if all users should be retrieved
role (String) The role or null, if all users should be retrieved
login (String) The login or null, if all users should be retrieved
count (Number) The max count of list items
sortBy (String) (Optional) field to sort the list of users by
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the results array.


update(login, changes, token)

Update a user into Account Manager

Param Type Description
login (String) The login of the user to update
changes (Object) The changes to the user details
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the updated user.


grant(login, role, scope, token)

Grant a role to a user into Account Manager

Param Type Description
login (String) The login (email) of the user
role (String) The role to grant
scope (String) The scope of the role to revoke
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the changed user.


revoke(login, role, scope, token)

Revoke a role to a user from Account Manager

Param Type Description
login (String) The login (email) of the user
role (String) The role to grant
scope (String) The scope of the role to revoke
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the changed user.


delete(login, purge, token)

Delete a user from Account Manager

Param Type Description
login (String) The user to delete
purge (Boolean) Whether to purge the user completely
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is a boolean value that confirms if the user has been deleted or not.


createLocal(instance, login, user, token)

Creates a new local user on an instance

Param Type Description
instance (String) The instance to create the user on
login (String) The user to delete
user (Object) The user details
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the created user.


searchLocal(instance, login, query, role, sortBy, count, start, token)

Search for local users on an instance

Param Type Description
instance (String) The instance to create the user on
login (String) The login or null, if all users should be retrieved
query (String) The query to search users for
role (String) The role to search users for
sortBy (String) (Optional) field to sort users by
count (Number) (Optional) number of items per page
start (Number) (Optional) zero-based index of the first search hit to include
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the results of the search.


updateLocal(instance, login, changes, token)

Update a local user on an instance

Param Type Description
instance (String) The instance to update the user on
login (String) The login of the local user to update
changes (Object) The changes to the user details
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the updated user.


grantLocal(instance, login, role, token)

Grant a role to a local user on an instance

Param Type Description
instance (String) The instance to apply the role on the user on
login (String) The login of the local user to grant
role (String) The role to grant
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the changed user.


revokeLocal(instance, login, role, token)

Revoke a role from a local user on an instance

Param Type Description
instance (String) The instance to apply the role on the user on
login (String) The login of the local user to revoke
role (String) The role to revoke
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is the changed user.


deleteLocal(instance, login, token)

Delete a local user from an instance

Param Type Description
instance (String) The instance to delete the user on
login (String) The login of the local user to delete
token (String) The Oauth token to use use for authentication

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is a boolean value that confirms if the user has been deleted or not.


Roles

APIs available in require('sfcc-ci').role:

List all the roles.

list(token, count)

Param Type Description
token (String) The Oauth token to use use for authentication
count (Number) count the max count of list items

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is a boolean value that confirms if the user has been deleted or not.


listLocal(instance, role, query, token, sortBy, count)

List all the roles into an instance.

Param Type Description
instance (String) The instance to list the role on
role (String) The role to revoke
query (String) The query to search role for
token (String) The Oauth token to use use for authentication
sortBy (String) (Optional) field to sort users by
count (Number) (Optional) number of items per page

Returns: (Promise) The Promise with its resolve or reject methods called respectively with the result or the error. The result variable here is a boolean value that confirms if the user has been deleted or not.


Manifest

APIs available in require('sfcc-ci').manifest:

generate(directories, ignorePatterns, targetDirectory, fileName)

Generates the manifest file based on the given local directories.

Param Type Description
directories (Array) The list of directories for which to generate a manifest. These directories has to contain a cartridges folder at their root level
ignorePatterns (Optional) (String) A list of glob patterns to use to ignore files while listing local files and generating the local manifest. If not provided, the default patterns are used: ['test/**/*', 'coverage/**/*', 'documentation/**/*', 'docs/**/*', '*.md']
targetDirectory (Optional) (Boolean) The directory where to store the generated manifest. If not provided, process.cwd() is used.
fileName (Optional) (Boolean) The file name to use while generating the manifest file. If not provided, the require('sfcc-ci').manifest.FILENAME constant is used.

Returns: (Promise) Returns a Promise. The resolve method is called with newly generated manifest file path as parameter The reject method is called with any error message if an error occurs during the comparison process

Example:

const sfcc = require('sfcc-ci');

const directories = ['/path/to/repo1', '/path/to/repo2'];
const ignorePatterns = ['test/**/*', 'docs/**/*'];
const targetDirectory = 'path/to/target/directory';
const fileName = 'my_manifest.json';

sfcc.manifest.generate(directories, ignorePatterns, targetDirectory, fileName)
    .then(manifestPath => {
        // do something with the manifest path
    })
    .catch(err => console.log(err));

WebDAV

APIs available in require('sfcc').webdav:

upload(instance, path, file, token, options, callback)

Uploads an arbitrary file onto a Commerce Cloud instance.

Param Type Description
instance (String) The instance to upload the import file to
path (String) The path relative to .../webdav/Sites where the file to upload to
file (String) The file to upload
token (String) The Oauth token to use use for authentication
options (Object) The options parameter can contains two properties: pfx: the path to the client certificate to use for two factor authentication. passphrase: the optional passphrase to use with the client certificate
callback (Function) Callback function executed as a result. The error will be passed as parameter to the callback function.

Returns: (void) Function has no return value


sfcc-ci's People

Contributors

al-haras avatar cc-prodsec avatar challmannsf avatar clavery avatar dependabot[bot] avatar dmersiowsky avatar ecrobertengel avatar eviljordan avatar hnestmann avatar jbachelet avatar johnboxall avatar jordanebachelet avatar ketan9190 avatar lisunovdv avatar mahdimontgomery avatar martin-dodo-hartmann avatar matt-rose-salesforce avatar nickpalmigiano avatar rlacydemandware avatar rsexton404 avatar sandragolden avatar sanjaykesavan avatar sgambolati avatar sgd1953 avatar snyk-bot avatar stevemartina-salesforce avatar svc-scm avatar tobiaslohr avatar wundrian avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sfcc-ci's Issues

Incremental code push support

@hnestmann @tobiaslohr
feel free to mark it as duplicate but this is what -to my view- we've concluded (After #20 discussion):
2 types of support

  • file detail level
    using a kind of deploymentinfo.json file as parameter (created from SCM info as a preprocess before calling sfcc-ci) that keeps track of every single file (vs last deployed code version) added/removeed/changed
  • cartridge level
    pushing the whole list (as parameter) of cartridges you wanna completely overwrite (no diff, just replace every cartridge in the list of the last deployed code version)
  • (there could be a folder level too)
    working as cartridge level one but only for listed cartridge (even using wildcards) +folder/subfolder (i.e. static folders)

Thanks

Ambiguous option -h for sandbox:get

option -h not working for help text with sfcc-ci sandbox:get, as -his used for local return of sandbox hostname. suggestion to remove local shortcut -h for command sandbox:get and only have --host

Code deployment to support activation of new code as single operation

Usually code deployments are done in several steps, including

  1. upload of the code as packaged zip archive to the instance,
  2. followed by an unzip of the archive on the server resulting in an extracted folder containing the single code artefacts and
  3. a deletion of the uploaded zip file

These steps are bundled together as a single CLI command sfcc-ci code:deploy.

The activation of the new code version however, comes as a separate command sfcc-ci code:activate, whereas in the majority of cases, the newly deployed code version is always activated after the code deployment.

Proposed change is a new option --activate with the sfcc-ci code:deploy which does the activation as step 4 of the code deployment sequence.

Error: mac verify failure

I'm trying to test the upload (interactively) using 2FA but I'm getting the error: Error: mac verify failure.

I'm using the following command (I replaced sensitive areas with "xxxx")

$ ./sfcc-ci-macos -D code:deploy ./2_6_0.zip -i staging.store.xxxxxx.demandware.net -c ./twofactor/store.xxxxx/store.xxxxx.p12 -p `cat ./twofactor/store.xxxxx/cert.staging.store.xxx.demandware.net_02.txt`
[DEBUG] No dw.json found in /Users/jorgematos/Repos/xxxxxx-Store/build
[DEBUG] Using alternative Oauth local port 7070 defined in env var `SFCC_OAUTH_LOCAL_PORT`
REQUEST { baseUrl: 'https://staging.store.xxxxx.demandware.net',
  uri: '/on/demandware.servlet/webdav/Sites/cartridges/2_6_0.zip',
  auth: { bearer: 'xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxx' },
  strictSSL: true,
  method: 'PUT',
  agentOptions:
   { pfx: <Buffer 30 82 0d e8 02 01 03 30 82 0d ae  ... >,
     passphrase: 'xxxxxxxxxxxxxxxxxxxxxxxxxx' },
  callback: [Function] }
REQUEST make request https://staging.store.xxxxx.demandware.net/on/demandware.servlet/webdav/Sites/cartridges/2_6_0.zip
Error: An error occured. Try running the command again with -D,--debug flag.
[DEBUG] Error code: undefined, message: mac verify failure, stack: Error: mac verify failure
    at Error (native)
    at Object.createSecureContext (_tls_common.js:131:17)
    at Object.exports.connect (_tls_wrap.js:1033:48)
    at Agent.createConnection (https.js:82:22)
    at Agent.createSocket (_http_agent.js:195:26)
    at Agent.addRequest (_http_agent.js:157:10)
    at new ClientRequest (_http_client.js:160:16)
    at Object.exports.request (http.js:31:10)
    at Object.exports.request (https.js:202:15)
    at Request.start (/snapshot/sfcc-ci/node_modules/request/request.js:751:32)

I'm not sure why I'm getting this, the path to the .p12 file is correct and so is the passphrase.

User Managment: role:list gets Account Manager Roles

We are currently using the latest version of the user management branch. A very helpful enhancement that could be made the matches some of the other commands is to add sfcc-ci role:list defaults to displaying the available roles in Account Manager if no --instance is passed in. This would allow us to query what roles are available and utilize that output. Would also be really helpful if you added either a scope:list or something along that line that would allow us to query all the currently available scopes to an organization.

Refactor sandbox:get

The sandbox command is currently the only one having a dedicated getter. This should be migrated to

sfcc-ci sandbox:list --sandbox zzzz-001 

Originally posted by @hnestmann in #47

Allow optional code version name to be passed to code:deploy

Allow optional code version name to be passed to command code:deploy which creates the code version as given explicitly instead of implicitly through top level folder(s) inside the deployed archive.

This allows more control over the actual code version creation and avoids the cartridges to be copied to a top level folder which is zipped and deployed.

Remove instance:save and instance:state:reset

Instance state save and reset functionality is based on a Commerce Cloud beta feature introduced before B2C Developer Sandboxes have been made available. With the B2C Developer Sandboxes in beta today and soon to launch GA, this state save and state reset functionalities are no longer needed and shall be removed.

Improve readme sections

Hello,

some remarks from my experience trying to install sfcc-ci.
To say the least it's not good.

"Configuration" section
The snippets for the JSON are incomplete. They should show the whole JSON.

"Installation Instructions" section
I am on Windows and nothing works as expected.

  1. no mention of the 2FA limitations for clone a repository by command line
  2. the curl command line does not work too
  3. the npm install does not create the client binary or add it to the path, so running sfcc-ci --help does not work
  4. "In case you encouter any issues with running sfcc-ci, you may run npm link to create a symbolic link", it should state that running npm link will enable the sfcc-ci "client" to run from the command line.

"Configuration"
Missing Windows path for the CLI settings.

"Environment Variables"
Is any action needed?

"CLI Examples"
The "export" command is not supported on Windows, I used "set" instead.

$API_KEY -> does not work on Windows, %API_KEY% does

sfcc-ci auth:login %API_KEY% -> OAuth2 Error Page with "loading..."

"Note, that you have to configure your API client to use redirect url http://localhost:8080." -> how?

sfcc-ci client:auth %API_KEY% %API_SECRET% %API_USER% %API_USER_PW% -> Error: Authentication failed: Resource owner authentication failed

Could you please update the sections to provide a complete set of instructions?

How to run locally

Using source code if I don't want to install sfcc-ci globally and run it locally using npm run sfcc-ci how do I do that ? It says sfcc-ci doesn't exists !

CLI tests broken

CLI test scripts are broken, due to underlying API server changes.

  1. Updating default sandbox TTL fails with exceeding value. Actual value to update to is 48, max supported is 24. Suggestion to update to 12.
  2. Reading actual values from server for restoring fails as sandbox realm model changed and property sandboxTTL has moved to property configuration.

Support interactive authentication for API key used in previous session

sfcc-ci auth:login should support authentication flow for interactive user authentication (via Oauth implicit flow) and honour API key of the previous session. The CLI currently memorizes the API key already in the local client configuration.

Running the command sfcc-ci auth:login may read the memorized API key and start the Oauth flow to authenticate the user interactively. This allows users who frequently authenticate via the same API key to re-authenticate without explicitly type the API key as a parameter of sfcc-ci auth:login $API_KEY

auth:login issue - error in console

While trying to login using CLI, i am getting the error on the browser window that is opened as a redirect. Error got: "Resource not found"

When i enabled the debug while executing the command(using -D), i am getting the following error in console:

[DEBUG] Configuration loaded from /Users/pgaur/dw.json
Using client secret from dw.json at /Users/pgaur
[DEBUG] Authorize via Oauth implicit grant
[DEBUG] Opening user agent with https://account.demandware.com/dwsso/oauth2/authorize?client_id=0fcb271a-ec93-4e80-b0b4-42049aa95824&redirect_uri=http://localhost:8080&response_type=token
[DEBUG] Local server for login redirect listening at http://localhost:8080
Waiting for user to authenticate...
Error: Authentication failed: Error: File '/**/sfcc-ci/resources/oauth2-redirect.html' was not included into executable at compilation stage. Please recompile adding it as asset or script.

This seems to be an issue with the binary itself, or is it something that i am missing?

Add project to github packages or npm

I am trying to setup a GitHub action that will use build-suite to build my site. Build-suite specifies this project as a github link in package.json. GitHub actions can't get the correct permissions to access this repository. The only work-around I have found is to fork this project into my GitHub Enterprise account and then change the build-suite package.json to reference that fork. Instead, can sfcc-ci be deployed to a package to the package managers. If you don't wish to push this project to NPM, a private package accessed through GitHub Packages might work.
Thank you.

auth:renew should grant new access token in client_credentials mode

Currently, to use auth:renew you have to have a refresh token, which is only issued on password grants, ie those where you supply username + password in addition to client id and secret.

When renew is called for a client_credentials grant, we should just create a new token with the AccountManager, which works just like the initial grant.

Release asset oauth2-redirect.html missing

Error: Authentication failed: Error: File 'C:**\sfcc-ci\resources\oauth2-redirect.html' was not included into executable at compilation stage. Please recompile adding it as asset or script.

Remove or convert console output to JSON when --json is given

When working non-interactively by calling the sfcc-ci program and specifying --json, for example like in the following case:

docker run docker-registry.releng.demandware.net/ccdx/dx-sfcc-ci:1.1.4-mbickel.refresh sandbox:list --json

The output may not be entirely json, for example when the authentication renewal kicks in and prints "Authentication succeeded" messages via calls to console.info to stdout.

This requires me to parse the stdout to figure out where the JSON object begins.

Can we change this so when --json is given, output is guaranteed to be a JSON object with any non-json output redirected to stderr, if necessary?

Getting "Network or Certificate Error" with Staging sfcc.instance.upload

I am able to successfully run a site import to my sandbox using the same script.

  1. I authorize to get a token
  2. I zip up my site data
  3. I start the upload with sfcc.instance.upload
  4. I run the import with sfcc.instance.import

This all works properly on my sandbox with OCAPI data API and WebDAV permissions setup to match what is in the README.md for this repo.

When I switch to using a staging url for the instance: cert.staging..demandware.net, I get the error and log:

Error: Network or certificate error
Error: An error occured. Try running the command again with -D,--debug flag.

I also have a script that uploads code using sfcc.code.deploy() using the same authentication methods for STG, and that works without issue.

I think I can rule out:

  1. WebDAV permissions since there are the same for dev01 and STG
  2. OCAPI permissions since the token generation works
  3. 2FA failure since the code deploy using the .p12 file and passphrase works for code.deploy(), but not for instance.upload()
  4. An issue with the sitedata_STG.zip since the data zip uploads successfully to dev01.

Can you look into this and let me know what the issue could be?

Webdav upload returns empty err object

callback(new Error(err));

Hi @tobiaslohr , I'm trying to use the webdav api for creating a new task for site template upload. And now I can see that task ends with some error. But when I've checked the error it shows me {};
empty_err_object
Here is the code snippet
webDavApi.upload(instanceUrl, options.release_path, archive, token, deployOptions, function (err) { if (err && err instanceof Error) { grunt.log.error(JSON.stringify(err)); done(false); } else { grunt.log.ok('Archive upload has been completed.'); done(); } });
Could you please check this moment and if possible provide more detailed error object in order to understand what is the issue.

Regards Oleksii.

P.S. It also will be good to have access to webdav delete functionality what currently is hidden.

Retrieving detail realm usage information

Sandbox API allows to pull detail realm usage information via GET /realms/{realm}/usage.

Task is to allow to pull that information via optional flag --show-usage for command sfcc-ci sandbox:realm:list, for example

sfcc-ci sandbox:realm:list --realm zzzz --show-usage

Error: Unsufficient Privileges

We are using the branch https://github.com/SalesforceCommerceCloud/sfcc-ci/tree/basic-user-mgmt and we have created a script to loop through a bunch of users and create their accounts and grant other user's permissions. The account creation portion is working but when trying to modify roles we get " DEBUG] {"errors":[{"message":"Cannot access com.demandware.am.common.model.Role bm_user for assigning to user XXXXXXXXXXXXXXXXXXX","code":"AccessDeniedException","fieldErrors":null}]}" (I X'd out the user ID for privacy) The account running this is an account admin as well as the api client were using has the following in default scope "roles
tenantFilter
profile"

One thing of note the api client's "Token Endpoint Auth Method" is set to client_secret_basic I am not sure if that matters or not. Is the reason were getting access denied is because this hasn't been brought into the master branch yet and therefore some back end changes need to happen on the Salesforce end to allow customer's to use this feature? If there is any additional info that I can provide let me know. This feature would be extremely useful in our ability to migrate to unified authentication and barring this working we will be stuck.

Download code version

For security reasons, we want to make sure the code we have in production is not changed manually.
For that, we want to be able to download the code version from webdav.

Use promises and async/await

Some modules are implemented using callback, which makes it hard to follow the order of execution when reading the code

Consume new Sandbox Aliases API

At the beginning of november, there will be new APIs for creating and assigning custom sandbox aliases for local testing. Please integrate these in sfcc-ci.

Exploring available instances

Adding separate feature request on behalf of @pfrickcol as raised in #61:

...Would also be really helpful if you added either a scope:list or something along that line that would allow us to query all the currently available scopes to an organization.

in programmatic API, callback for auth function has parameters in reverse order

Hi,

In lib/auth.js, the api version of the auth method has a callback(token, err) signature instead of the standard error-first format callback(err, token).
In addition, callback signature is not documented in the readme.
As a consequence, any developer with experience in node.js will get broken code at first try, and will lose time debugging.

Issue is located in this function call:

obtainToken(null, client_id, client_secret, null, function (err, res) {

obtainToken(null, client_id, client_secret, null, function (err, res) {
            if (!err && res.statusCode == 200) {
                // if successful, callback with token
                callback(res.body.access_token, undefined);
                return
            }
            // in case of errors, callback with err
            callback(undefined, new Error(err));
            return;
});

it should rather be

obtainToken(null, client_id, client_secret, null, function (err, res) {
            if (err || res.statusCode !== 200) {
                // handle error first
                return callback(new Error(err));
            }
            // base case
            return callback(undefined, res.body.access_token);
});

When rewriting the code this way, we can also see that the case where there isn't any error, but status code isn't 200 will give null to Error constructor, causing an issue which would be hard to trace.
As I'm already nitpicking ;) : the callback of obtainToken has the response as second parameter.
I think the naming obtainToken kind of hints that this function should handle the responsibility of validating the response and extracting the token instead of deferring that to calling code through a callback.

Regards,
Damien L.

auth:login not working

Just tried using the MACOS version of the binary and when I tried the auth:login feature interactively, the browser page opened to the URL but no content was shown, the browser tools shows that there are a few 404 errors.

I also tried building the code using npm and tried that and got the same issue.

The errors in the browser console are below (using Chrome for MAC).

2019-04-26_1537

My login URL: https://account.demandware.com/dwsso/oauth2/authorize?client_id=[I removed this]&redirect_uri=http://localhost:8080&response_type=token

Please advise.

Make client:auth more robust when login url cannot be reached

In some cases, when the login url of the authorization server (the Account Manager) cannot be reached, an exception is thrown and the command sfcc-ci client:auth does not gracefully print an error message but prints the stack trace to the console:

./node_modules/sfcc-ci/cli.js client:auth **** **** 

.../node_modules/sfcc-ci/lib/auth.js:235 } else if ( res.body && res.body['error_description']) { ^ TypeError: Cannot read property 'body' of undefined at Request._callback (.../node_modules/sfcc-ci/lib/auth.js:235:24) 
at self.callback (.../node_modules/request/request.js:185:22) 
at emitOne (events.js:96:13) 
at Request.emit (events.js:188:7) 
at Request.onRequestError (.../node_modules/request/request.js:881:8) 
at emitOne (events.js:96:13) 
at ClientRequest.emit (events.js:188:7) 
at TLSSocket.socketErrorListener (_http_client.js:314:9) 
at emitOne (events.js:96:13) 
at TLSSocket.emit (events.js:188:7)

Suggestion is the check on the response object being available and fallback to the err message passed to the callback function of the request module.

Expose deleteFile method for external usage

function deleteFile(instance, path, file, token, ignoreLocalFilePath, options, callback) {

Hi @tobiaslohr, I can see that you have nice method for deleting files on instance via webdav but we can't use it in our purposes. It will be nice to have such possibility as part of available webdav api.
So if it possible and you will have time for it please provide us deleteFile webdav api.

Many thanks, Oleksii.

Auto-detect OCAPI Version

Is there potential when selecting your instance to leverage the API version returned a separate call to /dw/meta/v1/rest/data?

NPM Audit Security Report

There is one package that is a current dependency and cannot be automatically fixed using "npm audit fix"

                   === npm audit security report ===


                             Manual Review
         Some vulnerabilities require your attention to resolve

      Visit https://go.npm.me/audit-guide for additional guidance

High Insufficient Entropy

Package cryptiles

Patched in >=4.1.2

Dependency of pkg [dev]

Path pkg > pkg-fetch > request > hawk > cryptiles

More info https://nodesecurity.io/advisories/720

found 1 high severity vulnerability in 1570 scanned packages
1 vulnerability requires manual review. See the full report for details.

Import result always OK

I'm trying to import XML files into a sandbox. If the XMLs do not contain no error, everything is fine. The problem comes when they contain errors, because I'm unable to get anything that indicates that the import has failed.

I checked both the import() callback error parameter and the status of the job (sfcc-site-archive-import) that performs the import. But no error es reported at all. The job always return status OK, which I would say that it should not.

The only option I see would be to parse the log file produced by the job, but there is not even a function to download the file

job-response.txt

sandbox.js: Handle unexpected error message gracefully

Currently, sandbox.js expects two different objects on the response body (error.message and message) when the statuscode is above 400. At least the error.message property is documented on the CCDX API.

But when the API fails to honor it's contract or an intermediary responds with an unexpected error code the output from sfcc-ci is a rather non-intuitive "TypeError: Cannot read property 'message' of undefined"

At least output the status code so I don't have to guess at the state of the system.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.