Salto for
NetSuite
Articles
SHARE
Eric Grubaugh
June 19, 2023
13
min read
About Salto: Salto's platform helps you and your team deploy, track, and manage your NetSuite customizations effortlessly. Learn more here.
In Part 1 of this series, we discussed the basic definitions and potential benefits of Continuous Integration and Continuous Deployment. In this second part, we create a functioning Continuous Deployment pipeline using the SuiteCloud Development Framework (SDF) and GitHub Actions.
This article is not intended to grant you mastery over all things GitHub Actions; GitHub has already written that documentation for you.
This article is intended to help you establish a simple Continuous Deployment pipeline using GitHub Actions which you can then use to learn and experiment with the possibilities. I strongly urge you to use a test Project, a test Repository, and a Sandbox account while you are learning.
This article assumes you have installed, have access to, and have a working knowledge of:
We’ll demonstrate our Continuous Deployment pipeline using a brand new git repository and SDF Project. Instrumenting your existing SDF Project(s) will be left as an exercise for you. This initial setup section borrows heavily from GitHub’s Quick Start guide for Actions.
We start by creating a new Account Customization SDF Project and including the Unit Test Framework; this will initialize our SDF Project as an npm package as well. You can name the Project whatever you like. I named my Project and Repository actions-sdf.
Now we need a git repository to connect with our Project, so we log in to our GitHub account and create a new Repository. Once the repository exists, copy its URL:
Head back to your terminal and link your SDF Project to your new Repository:
Push the initial Project contents to the Repository’s default branch; my default branch is called main:
Create a new git branch where we’ll add the demo GitHub Actions configuration:
The top level of organization for GitHub Actions are called Workflows. Workflows are defined as YAML files which live in a Repository under <repoRoot>/.github/workflows/. Create those directories now along with a new YAML file which will hold our demo configuration. I’m naming mine github-actions-demo.yml:
Add the following contents to github-actions-demo.yml (again this content is borrowed straight from GitHub’s Actions Quick Start guide):
We won’t go through each line of this as most of them explain themselves, but we’ll hit the highlights:
First, we give our Workflow a readable name GitHub Actions Demo. This is the static name that identifies the Workflow and will be displayed in the list of Workflows under the Actions tab of our Repository on GitHub.
Next, we provide a name that will be generated each time our Workflow is run. This example only dynamically displays the user that triggered the Workflow. Alternatively, this property could be used to generate a unique identifier for each run, like a build number or a date/time stamp.
Then we define what Repository events will trigger our Workflow. Here we state that this Workflow should run anytime anyone pushes new code anywhere in our Repository.
In practice, you’ll likely want much more specific conditions and triggers for your Workflow(s). We’ll look at one example of that near the end of the article, but know that there are a ton of options for you.
A Workflow consists of Jobs. Each Job is keyed with an identifier and requires a Runner - a virtual machine operating system to execute within. Our Workflow consists of a single Job identified as Explore-GitHub-Actions which runs in an Ubuntu VM. The Job’s identifier will be displayed in the Workflow visualization on the GitHub UI, so make sure it’s recognizable.
If a Workflow consists of multiple Jobs, each Job will run in its own separate Runner, and all Jobs will run in parallel (unless you define them to do otherwise).
The actual activities a Job performs are defined as Steps. Steps can be defined in a variety of ways:
Our example Job runs a variety of commands and dynamically reads values from various environment variables using the ${{ }} syntax.
Push this new code to your Repository, and the GitHub Actions Demo Workflow will be automatically triggered; you can view its results by navigating to the Actions tab of your Repository, selecting the Workflow in the sidebar, and selecting the current run of the Workflow.
Feel free to experiment and modify this Workflow as much as you wish, exploring the GitHub Actions docs as you do. Once you’re ready to move on, disable the demo Workflow by navigating to the Workflow in the GitHub UI, selecting the ... menu at the top right, and selecting Disable workflow. We don’t need this example running every time a push occurs in the Repository.
Now that we have seen GitHub Actions work, let’s do what we actually came here to do and add SDF and NetSuite into the mix.
We’ll start by updating the default package.json file which SDF created for us; primarily we need to add the SDF CLI as a dependency so that the GitHub runner will know to install it. Replace the contents of your Project’s package.json file with the following:
The most significant difference from the default file is the addition of the @oracle/suitecloud-cli package as a devDependency. I’ve additionally named my npm package the same as my Project and Repository, though the name can be whatever you want, and I’ve given it a version number more appropriate to a proof-of-concept Project.
If you’re not familiar with the package.json file, you can read all about its functionality here.
With these updates made, we’re going to make sure the test script correctly invokes the Jest unit test suite which SDF generated during Project creation. In your terminal, from the Project directory:
We should then see successful Jest output in our terminal.
Now that we know our package is configured correctly locally, let’s get our unit test suite running within GitHub Actions. While you could re-purpose the previous Workflow, I also want to illustrate that a Repository can have any number of Workflows defined in its .github/workflows directory.
Create a new Workflow configuration file in .github/workflows; I’m calling mine sdf-validate.xml.
We’ll start the Workflow out the same way as the previous configuration, changing the relevant names, and to start we only need to check out the Repository code.
The SDF CLI has some operating system dependencies that need to be installed before it will run correctly - namely, node.js and a Java Development Kit (at the time of this writing, it must be Version 17). Luckily, these are extremely common dependencies, so GitHub has already created Actions that will install these for you.
After our checkout Step, we’ll add the current “Long-Term Support” version of node.js using the setup-node Action:
Following that, we’ll do the same for JDK version 17 using the setup-java Action:
With these dependencies in place, we can replicate the installation and test commands we ran locally in our Workflow by adding them as Steps:
There is a subtle but important difference here in that we are using npm ci instead of npm install to perform the package installation. You can read about the details of the ci command yourself, but the primary significance of the ci command is that it’s designed for use in a Continuous Integration environment (like GitHub Actions) and performs a clean install each execution.
Push this new code to your Repository, then navigate your way through the Actions tab to see the results. You should see outputs similar to the following under each Step in the sdf-validate Job:
To see what happens when your unit tests fail, edit the __tests__/sample-test.js like so:
Push this change, and your unit test should fail, thus causing the Workflow to exit with a failure status:
Now restore the test to its working state, and we’ll move on to validating and deploying our Project.
In order to interact with NetSuite via SDF, your Workflow will need a valid NetSuite access token. Begin by creating a new token with an appropriate Role in your target account(s); the native “Developer” role is a fine default if you don’t have a more specific one.
Next, we need a safe place to store that token information.
GitHub Actions provides us with the Secrets mechanism for storing sensitive data like token values and passwords. In order to store our token information as Secrets, we first need to create an Environment.
Navigate to your Repository > Settings > Environments. Once there, create a new Environment that will represent your target NetSuite account. You may name it whatever you like; I created one named production to represent my Production account and one named sandbox to represent my demo account.
Within your new Environment, create a new Environment Variable to store your target account’s ID. I named my variable NS_ACCOUNT_ID. Next, add two new Environment Secrets to store your token information. I named my secrets NS_TOKEN_ID and NS_TOKEN_SECRET to store the Token ID and Token Secret values, respectively. These variables will let us reference our values programmatically within our Workflow configuration rather than hardcoding the values.
It’s a good idea to prefix environment variables/secrets with an identifier for the corresponding system (e.g. NS_ for NetSuite) as it’s fairly likely your GitHub Actions might communicate with and store information for several systems (e.g. Slack, Jira, NetSuite, etc).
Repeat the Token and Environment creation steps for any additional target NetSuite accounts you might want to use.
Now we should be able to authenticate to NetSuite within our Workflow. Back in the sdf-validate Job, we need to tell the Job which Environment to use; we do so by adding an environment property to the Job definition:
You can specify the name of any of the Environments you just created; once again, I strongly recommend using a Sandbox account while you are learning and testing.
With an Environment assigned, the Job can now access the Environment’s Variables via the vars context and its Secrets via the secrets context.
Add a new Step for authentication using the account:savetoken SDF command.
Note that I have to add the fully qualified path to the suitecloud command; this is because the node_modules/.bin/ directory is not on our PATH by default. To avoid this, you could add a Step in the Job to do so, but I leave that as an exercise for you.
Push this change, then monitor the Job’s output to see if authentication is working.
Once your Workflow can authenticate to NetSuite, it can start to leverage SDF to do some work! One thing we nearly always want to do before we deploy an SDF Project is validate it. Personally, I like to validate using the project:deploy command with its dryrun option (if you want to learn why I prefer that, check out the aforementioned SDF course on Salto Leap).
Instead of just adding a Step to our Job which invokes SDF directly, though, I’m going to make a validate script within our npm package definition, and the Job will invoke that script instead. The main reason I do this is so I can run the exact same command both from my local machine and within GitHub Actions; this helps to ensure consistency and avoid any gaps between the two environments.
In package.json add a new validate property to the scripts Object:
Then in your Workflow, add a new Step to invoke this validate script using the npm run command:
A secondary benefit of using npm scripts to run suitecloud operations is that I no longer have to specify the full path to the command like I did with the authentication step; npm knows about the node_modules/.bin/ path by default, whereas GitHub Actions does not.
As usual, push these additions to the repository and observe the validation of your SDF Project within your Actions Workflow.
If validation were to fail, the Job would exit without proceeding on to deployment (once we add that step … right now).
Within our Project successfully validating, it’s finally time to deploy it to NetSuite. This will unfold in exactly the same way as validation.
First we add a deploy script to our npm package:
Then we add a Step to our Job to invoke the new script:
Once we push these changes, we should see the Workflow successfully deploy our SDF Project.
Since we’re so far testing this on an empty SDF Project (no source files or Object definitions), perhaps the actual results of validation and deployment aren’t that interesting, but we can clearly see the SDF commands being invoked, contacting our NetSuite account, and returning appropriate results.
Before you start adding in a few files and Objects of your own to make the results more interesting and realistic (which you totally should do, just not yet), remember that this Workflow is executed whenever anyone pushes any changes on any branch in our Repository. In practice, that is very likely not what you want, especially for a Production environment.
Let’s ensure that only pushes on the main branch will trigger a deployment to our Environment.
First, we establish a Branch Protection Rule on our Environment. While in practice you would likely do this only for your Production Environment, for testing and learning purposes, you can set this up on your Sandbox Environment as well.
In your Environment definition, add a new Deployment Branch, and specify the default branch in your Repository; again mine is named main:
From now on, any Jobs that target this Environment will immediately fail unless they’re triggered from the main branch.
Additionally, we can restrict our entire Workflow so that it only responds to push events on the main branch. Back in the Workflow configuration, we want to modify the on property near the top like so:
When you push this change to your repository, assuming you are still operating on a branch other than main, observe that the Workflow does not get triggered. Only push events on the main branch will trigger our Workflow (and thus a deployment).
At this point, you have a fully functioning Continuous Deployment pipeline using SDF within GitHub Actions. It runs your unit tests, validates your SDF Project, and if all goes well, deploys the Project to NetSuite.
You can find all of my example code over in my GitHub Repository.
Next, you might check out GitHub’s Starter Workflows for basic configuration examples, and you might read up on npm scripts and lifecycles to see what else you might be able to accomplish with those.
Some ideas for what else your Workflow could do for you:
I’ve introduced the major building blocks of GitHub Actions in Workflows, Jobs, and Environments, and I’ve shown how to use SDF in that construction, and I’ll be back in Part 3 of the series to ramp up the complexity of our Workflow. For now, it’s your turn to build something great with those blocks!
Salto for
NetSuite
NetSuite
SHARE
Eric Grubaugh
June 19, 2023
13
min read
About Salto: Salto's platform helps you and your team deploy, track, and manage your NetSuite customizations effortlessly. Learn more here.
In Part 1 of this series, we discussed the basic definitions and potential benefits of Continuous Integration and Continuous Deployment. In this second part, we create a functioning Continuous Deployment pipeline using the SuiteCloud Development Framework (SDF) and GitHub Actions.
This article is not intended to grant you mastery over all things GitHub Actions; GitHub has already written that documentation for you.
This article is intended to help you establish a simple Continuous Deployment pipeline using GitHub Actions which you can then use to learn and experiment with the possibilities. I strongly urge you to use a test Project, a test Repository, and a Sandbox account while you are learning.
This article assumes you have installed, have access to, and have a working knowledge of:
We’ll demonstrate our Continuous Deployment pipeline using a brand new git repository and SDF Project. Instrumenting your existing SDF Project(s) will be left as an exercise for you. This initial setup section borrows heavily from GitHub’s Quick Start guide for Actions.
We start by creating a new Account Customization SDF Project and including the Unit Test Framework; this will initialize our SDF Project as an npm package as well. You can name the Project whatever you like. I named my Project and Repository actions-sdf.
Now we need a git repository to connect with our Project, so we log in to our GitHub account and create a new Repository. Once the repository exists, copy its URL:
Head back to your terminal and link your SDF Project to your new Repository:
Push the initial Project contents to the Repository’s default branch; my default branch is called main:
Create a new git branch where we’ll add the demo GitHub Actions configuration:
The top level of organization for GitHub Actions are called Workflows. Workflows are defined as YAML files which live in a Repository under <repoRoot>/.github/workflows/. Create those directories now along with a new YAML file which will hold our demo configuration. I’m naming mine github-actions-demo.yml:
Add the following contents to github-actions-demo.yml (again this content is borrowed straight from GitHub’s Actions Quick Start guide):
We won’t go through each line of this as most of them explain themselves, but we’ll hit the highlights:
First, we give our Workflow a readable name GitHub Actions Demo. This is the static name that identifies the Workflow and will be displayed in the list of Workflows under the Actions tab of our Repository on GitHub.
Next, we provide a name that will be generated each time our Workflow is run. This example only dynamically displays the user that triggered the Workflow. Alternatively, this property could be used to generate a unique identifier for each run, like a build number or a date/time stamp.
Then we define what Repository events will trigger our Workflow. Here we state that this Workflow should run anytime anyone pushes new code anywhere in our Repository.
In practice, you’ll likely want much more specific conditions and triggers for your Workflow(s). We’ll look at one example of that near the end of the article, but know that there are a ton of options for you.
A Workflow consists of Jobs. Each Job is keyed with an identifier and requires a Runner - a virtual machine operating system to execute within. Our Workflow consists of a single Job identified as Explore-GitHub-Actions which runs in an Ubuntu VM. The Job’s identifier will be displayed in the Workflow visualization on the GitHub UI, so make sure it’s recognizable.
If a Workflow consists of multiple Jobs, each Job will run in its own separate Runner, and all Jobs will run in parallel (unless you define them to do otherwise).
The actual activities a Job performs are defined as Steps. Steps can be defined in a variety of ways:
Our example Job runs a variety of commands and dynamically reads values from various environment variables using the ${{ }} syntax.
Push this new code to your Repository, and the GitHub Actions Demo Workflow will be automatically triggered; you can view its results by navigating to the Actions tab of your Repository, selecting the Workflow in the sidebar, and selecting the current run of the Workflow.
Feel free to experiment and modify this Workflow as much as you wish, exploring the GitHub Actions docs as you do. Once you’re ready to move on, disable the demo Workflow by navigating to the Workflow in the GitHub UI, selecting the ... menu at the top right, and selecting Disable workflow. We don’t need this example running every time a push occurs in the Repository.
Now that we have seen GitHub Actions work, let’s do what we actually came here to do and add SDF and NetSuite into the mix.
We’ll start by updating the default package.json file which SDF created for us; primarily we need to add the SDF CLI as a dependency so that the GitHub runner will know to install it. Replace the contents of your Project’s package.json file with the following:
The most significant difference from the default file is the addition of the @oracle/suitecloud-cli package as a devDependency. I’ve additionally named my npm package the same as my Project and Repository, though the name can be whatever you want, and I’ve given it a version number more appropriate to a proof-of-concept Project.
If you’re not familiar with the package.json file, you can read all about its functionality here.
With these updates made, we’re going to make sure the test script correctly invokes the Jest unit test suite which SDF generated during Project creation. In your terminal, from the Project directory:
We should then see successful Jest output in our terminal.
Now that we know our package is configured correctly locally, let’s get our unit test suite running within GitHub Actions. While you could re-purpose the previous Workflow, I also want to illustrate that a Repository can have any number of Workflows defined in its .github/workflows directory.
Create a new Workflow configuration file in .github/workflows; I’m calling mine sdf-validate.xml.
We’ll start the Workflow out the same way as the previous configuration, changing the relevant names, and to start we only need to check out the Repository code.
The SDF CLI has some operating system dependencies that need to be installed before it will run correctly - namely, node.js and a Java Development Kit (at the time of this writing, it must be Version 17). Luckily, these are extremely common dependencies, so GitHub has already created Actions that will install these for you.
After our checkout Step, we’ll add the current “Long-Term Support” version of node.js using the setup-node Action:
Following that, we’ll do the same for JDK version 17 using the setup-java Action:
With these dependencies in place, we can replicate the installation and test commands we ran locally in our Workflow by adding them as Steps:
There is a subtle but important difference here in that we are using npm ci instead of npm install to perform the package installation. You can read about the details of the ci command yourself, but the primary significance of the ci command is that it’s designed for use in a Continuous Integration environment (like GitHub Actions) and performs a clean install each execution.
Push this new code to your Repository, then navigate your way through the Actions tab to see the results. You should see outputs similar to the following under each Step in the sdf-validate Job:
To see what happens when your unit tests fail, edit the __tests__/sample-test.js like so:
Push this change, and your unit test should fail, thus causing the Workflow to exit with a failure status:
Now restore the test to its working state, and we’ll move on to validating and deploying our Project.
In order to interact with NetSuite via SDF, your Workflow will need a valid NetSuite access token. Begin by creating a new token with an appropriate Role in your target account(s); the native “Developer” role is a fine default if you don’t have a more specific one.
Next, we need a safe place to store that token information.
GitHub Actions provides us with the Secrets mechanism for storing sensitive data like token values and passwords. In order to store our token information as Secrets, we first need to create an Environment.
Navigate to your Repository > Settings > Environments. Once there, create a new Environment that will represent your target NetSuite account. You may name it whatever you like; I created one named production to represent my Production account and one named sandbox to represent my demo account.
Within your new Environment, create a new Environment Variable to store your target account’s ID. I named my variable NS_ACCOUNT_ID. Next, add two new Environment Secrets to store your token information. I named my secrets NS_TOKEN_ID and NS_TOKEN_SECRET to store the Token ID and Token Secret values, respectively. These variables will let us reference our values programmatically within our Workflow configuration rather than hardcoding the values.
It’s a good idea to prefix environment variables/secrets with an identifier for the corresponding system (e.g. NS_ for NetSuite) as it’s fairly likely your GitHub Actions might communicate with and store information for several systems (e.g. Slack, Jira, NetSuite, etc).
Repeat the Token and Environment creation steps for any additional target NetSuite accounts you might want to use.
Now we should be able to authenticate to NetSuite within our Workflow. Back in the sdf-validate Job, we need to tell the Job which Environment to use; we do so by adding an environment property to the Job definition:
You can specify the name of any of the Environments you just created; once again, I strongly recommend using a Sandbox account while you are learning and testing.
With an Environment assigned, the Job can now access the Environment’s Variables via the vars context and its Secrets via the secrets context.
Add a new Step for authentication using the account:savetoken SDF command.
Note that I have to add the fully qualified path to the suitecloud command; this is because the node_modules/.bin/ directory is not on our PATH by default. To avoid this, you could add a Step in the Job to do so, but I leave that as an exercise for you.
Push this change, then monitor the Job’s output to see if authentication is working.
Once your Workflow can authenticate to NetSuite, it can start to leverage SDF to do some work! One thing we nearly always want to do before we deploy an SDF Project is validate it. Personally, I like to validate using the project:deploy command with its dryrun option (if you want to learn why I prefer that, check out the aforementioned SDF course on Salto Leap).
Instead of just adding a Step to our Job which invokes SDF directly, though, I’m going to make a validate script within our npm package definition, and the Job will invoke that script instead. The main reason I do this is so I can run the exact same command both from my local machine and within GitHub Actions; this helps to ensure consistency and avoid any gaps between the two environments.
In package.json add a new validate property to the scripts Object:
Then in your Workflow, add a new Step to invoke this validate script using the npm run command:
A secondary benefit of using npm scripts to run suitecloud operations is that I no longer have to specify the full path to the command like I did with the authentication step; npm knows about the node_modules/.bin/ path by default, whereas GitHub Actions does not.
As usual, push these additions to the repository and observe the validation of your SDF Project within your Actions Workflow.
If validation were to fail, the Job would exit without proceeding on to deployment (once we add that step … right now).
Within our Project successfully validating, it’s finally time to deploy it to NetSuite. This will unfold in exactly the same way as validation.
First we add a deploy script to our npm package:
Then we add a Step to our Job to invoke the new script:
Once we push these changes, we should see the Workflow successfully deploy our SDF Project.
Since we’re so far testing this on an empty SDF Project (no source files or Object definitions), perhaps the actual results of validation and deployment aren’t that interesting, but we can clearly see the SDF commands being invoked, contacting our NetSuite account, and returning appropriate results.
Before you start adding in a few files and Objects of your own to make the results more interesting and realistic (which you totally should do, just not yet), remember that this Workflow is executed whenever anyone pushes any changes on any branch in our Repository. In practice, that is very likely not what you want, especially for a Production environment.
Let’s ensure that only pushes on the main branch will trigger a deployment to our Environment.
First, we establish a Branch Protection Rule on our Environment. While in practice you would likely do this only for your Production Environment, for testing and learning purposes, you can set this up on your Sandbox Environment as well.
In your Environment definition, add a new Deployment Branch, and specify the default branch in your Repository; again mine is named main:
From now on, any Jobs that target this Environment will immediately fail unless they’re triggered from the main branch.
Additionally, we can restrict our entire Workflow so that it only responds to push events on the main branch. Back in the Workflow configuration, we want to modify the on property near the top like so:
When you push this change to your repository, assuming you are still operating on a branch other than main, observe that the Workflow does not get triggered. Only push events on the main branch will trigger our Workflow (and thus a deployment).
At this point, you have a fully functioning Continuous Deployment pipeline using SDF within GitHub Actions. It runs your unit tests, validates your SDF Project, and if all goes well, deploys the Project to NetSuite.
You can find all of my example code over in my GitHub Repository.
Next, you might check out GitHub’s Starter Workflows for basic configuration examples, and you might read up on npm scripts and lifecycles to see what else you might be able to accomplish with those.
Some ideas for what else your Workflow could do for you:
I’ve introduced the major building blocks of GitHub Actions in Workflows, Jobs, and Environments, and I’ve shown how to use SDF in that construction, and I’ll be back in Part 3 of the series to ramp up the complexity of our Workflow. For now, it’s your turn to build something great with those blocks!