Salto for
NetSuite
Articles
SHARE
Eric Grubaugh
July 17, 2023
9
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 2 of the CI/CD for NetSuite Developers series, we established a working pipeline using SDF and GitHub Actions to automatically unit test, validate, and deploy an SDF project when pushing new changes to a git repository. That pipeline consisted of a single Workflow with a single Job.
In all honesty, this foundational setup will likely be sufficient for the vast majority of SuiteScript development use cases; however, there are still valuable concepts and lessons that can be learned from ramping up the complexity of our pipeline. These are what we’ll explore in Part 3:
Our first Workflow consisted of a single Job which contained several sequential Steps; the Steps of a Job are always executed serially. As our Project grows—particularly as we add significant numbers of unit tests, files, and Objects—the Steps that interact with these elements will require increasing amounts of time and resources. For Projects of sufficient size, it may become beneficial to parallelize some of these Steps.
In order to parallelize these processes, we need to split the Steps into multiple Jobs. Let’s update our initial Workflow to contain three Jobs: one for running the unit tests, one for validating the SDF Project, and one for deploying the SDF Project.
Note: While developing these changes, ensure you are using a Sandbox environment. You may want to adjust the triggers for your Workflow so that you do not have to push on the main branch to see the results of your changes.
We’re going to leave the existing sdf-validate Job and give it two sibling Jobs: unit-test and sdf-deploy.
We’ve extracted the appropriate Steps from the original sdf-validate Job to their respective new Jobs—the npm test Step moved to the unit-test Job, and the deployment Step moved to the sdf-deploy Job.
Note the sdf-deploy Job needs to repeat the Authentication Step. Notice also that each Job repeats the same installation Steps (checkout, install node, etc). This is because each Job executes in its own Runner, completely separate from the other Jobs in the Workflow. Thus, each Job needs to install the Project’s prerequisites into its Runner. This is the primary performance trade-off for parallelizing Jobs; you’ll have to assess for your own situation whether this is worth it for your operations.
When triggering this updated Workflow, you should see that all three Jobs execute at the same time. By default, GitHub Actions executes in parallel all the Jobs within a Workflow. It’s nice that parallelization doesn’t require any special action or handling from us, but this may not be exactly what we want in all cases.
For instance, you probably don’t want to deploy if either your unit tests or Project validation fails, but that is currently what will happen. It’s OK if the tests and validation occur simultaneously, but we should wait for both to succeed before we deploy—otherwise they’re not really doing their jobs.
To ensure a Job executes after other Jobs, you can use a Job’s needs parameter.
The value for needs can be a single Job ID or an Array of Job IDs. In this case, we want the sdf-deploy Job to wait for both unit-test and sdf-validate to complete:
Now when you trigger this Workflow, unit-test and sdf-validate will run first in parallel, and if both succeed, sdf-deploy will run afterwards. If either fails, sdf-deploy will be skipped and the Workflow will exit. This is almost certainly a more desirable behavior for Production code.
If you’re currently shaking your fist and shouting the word DRY at me through your monitor, I feel you; there’s a lot of repetition in this code (but do remember that DRY is about repeated facts, not necessarily repeated code, and that premature abstraction is perhaps worse than repeated code).
Pedantic soapboxing aside, “How to set up the Runner for SDF” is definitely a repeated fact in our current configuration. To eliminate those repeated steps, we can extract the installation steps into our own custom Action which GitHub calls a composite action. The full reference documentation can be found here.
Composite actions are defined in yet another YAML file named action.yml. This file could exist in the same repository or a separate one; for simplicity in this article, we’ll create our action in the same repository.
While the file must be named action.yml, it can live anywhere in our repository. For that reason, I think it makes sense to make a new actions folder under our existing .github/ directory as a sibling to our workflows directory. To differentiate this action.yml from any other custom actions we might want in this repository, let’s create it under .github/actions/sdf-install/:
In the new action.yml, we can add the initial configuration for our composite action:
Before we implement the steps, we need to examine them for any dynamic data they require. Most of the Steps are static, but in order to correctly authenticate, we need a NetSuite Account ID, Token ID, and Token Secret. Let’s add these values as parameters in our action so that we can pass in the requisite data.
The parameters for an Action are specified with the inputs property:
With our inputs in place, we can extract the repeated installation steps into the steps structure, then replace the old environment variable references with references to our new inputs:
Notice that the checkout step is missing from our implementation. This is because the Action lives in the repository, so we can’t perform the Action without first checking out the repository. Thus, we’ll still have to perform the checkout step from each Job.
Back in sdf-validate.yml, we’re ready to replace the repeated installation steps with a single call to our new custom Action. In each of the three Jobs, our steps can now start like so:
We invoke Actions with the uses command. Within a uses command, inputs are specified using the with structure. Here we pass in the environment variables and secrets that we were previously specifying directly in our authentication Step.
Triggering our Workflow again, we should expect to see exactly the same behavior as before, but now with much less repeated configuration.
For those of you embarking on this CI/CD journey with me, and for all NetSuite developers generally, I sincerely hope you have access to at least one non-Production account for learning and testing, though I know that’s not always the case. While the functionality of our pipeline is filling out nicely, it can only operate on a single, hard-coded environment. To change the pipeline from Sandbox to Production or back, you’d currently have to push a code change in the configuration file; that kind of manual interaction is the opposite of what we want from our automation pipeline.
Luckily for us, the environment property of a Job accepts not only names but expressions as well. This means we can dynamically select an Environment for a Job based on conditions or values set in the pipeline.
I prefer to follow a feature-branching strategy in my SuiteScript repositories, so ongoing development is done in feature branches while main is considered the stable, Production-ready code. Using that information, I can conditionally select which Environment my Jobs should use based on which branch has changed:
The branch name which triggered the Workflow is available in the github context’s ref_name property:
In practice, you probably don’t want to continuously/automatically deploy to a Sandbox or Production account, unless you are a solo developer. If a team of developers is sharing the same account and working in the same repository which deploys every feature branch push, they’d constantly be overwriting each others’ changes.
You might, however, want to introduce a manual approval step into your pipeline to allow a gatekeeper to decide whether a build gets deployed or not. We can do so via the Required Approvers setting on an Environment.
By checking the Required reviewers box and specifying appropriate users in an Environment’s settings, GitHub will pause each Job that targets this Environment and wait for manual approval from the listed users. It will notify all approvers that a build is pending their review, and approvers can then jump into GitHub and provide their approval or rejection of a build.
For me, the behavior of this approval isn’t quite what I want as it will request approval on every Job within the Workflow. I’d prefer to incorporate an approval as a Step within a Job or Workflow instead (this is actually how CircleCI, a “competitor” of GitHub Actions, handles this process).
There is a third-party Action that purports to solve this problem, but it leverages the repository’s Issues to provide approvals, and that’s also not ideal for me. If you’re curious, I leave the investigation and setup of this Action to you as an exercise.
At this point, we have a strong and flexible foundation for automating the testing, validation, and deployment of our SuiteScript code. You can find this complete configuration in the Part 3 Release of my GitHub repository.
From here, I hope you’ve seen enough that you feel comfortable and inspired to add and adapt this Workflow to your needs, and I hope it makes delivering your SuiteScript easier, faster, and more enjoyable.
Salto for
NetSuite
NetSuite
SHARE
Eric Grubaugh
July 17, 2023
9
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 2 of the CI/CD for NetSuite Developers series, we established a working pipeline using SDF and GitHub Actions to automatically unit test, validate, and deploy an SDF project when pushing new changes to a git repository. That pipeline consisted of a single Workflow with a single Job.
In all honesty, this foundational setup will likely be sufficient for the vast majority of SuiteScript development use cases; however, there are still valuable concepts and lessons that can be learned from ramping up the complexity of our pipeline. These are what we’ll explore in Part 3:
Our first Workflow consisted of a single Job which contained several sequential Steps; the Steps of a Job are always executed serially. As our Project grows—particularly as we add significant numbers of unit tests, files, and Objects—the Steps that interact with these elements will require increasing amounts of time and resources. For Projects of sufficient size, it may become beneficial to parallelize some of these Steps.
In order to parallelize these processes, we need to split the Steps into multiple Jobs. Let’s update our initial Workflow to contain three Jobs: one for running the unit tests, one for validating the SDF Project, and one for deploying the SDF Project.
Note: While developing these changes, ensure you are using a Sandbox environment. You may want to adjust the triggers for your Workflow so that you do not have to push on the main branch to see the results of your changes.
We’re going to leave the existing sdf-validate Job and give it two sibling Jobs: unit-test and sdf-deploy.
We’ve extracted the appropriate Steps from the original sdf-validate Job to their respective new Jobs—the npm test Step moved to the unit-test Job, and the deployment Step moved to the sdf-deploy Job.
Note the sdf-deploy Job needs to repeat the Authentication Step. Notice also that each Job repeats the same installation Steps (checkout, install node, etc). This is because each Job executes in its own Runner, completely separate from the other Jobs in the Workflow. Thus, each Job needs to install the Project’s prerequisites into its Runner. This is the primary performance trade-off for parallelizing Jobs; you’ll have to assess for your own situation whether this is worth it for your operations.
When triggering this updated Workflow, you should see that all three Jobs execute at the same time. By default, GitHub Actions executes in parallel all the Jobs within a Workflow. It’s nice that parallelization doesn’t require any special action or handling from us, but this may not be exactly what we want in all cases.
For instance, you probably don’t want to deploy if either your unit tests or Project validation fails, but that is currently what will happen. It’s OK if the tests and validation occur simultaneously, but we should wait for both to succeed before we deploy—otherwise they’re not really doing their jobs.
To ensure a Job executes after other Jobs, you can use a Job’s needs parameter.
The value for needs can be a single Job ID or an Array of Job IDs. In this case, we want the sdf-deploy Job to wait for both unit-test and sdf-validate to complete:
Now when you trigger this Workflow, unit-test and sdf-validate will run first in parallel, and if both succeed, sdf-deploy will run afterwards. If either fails, sdf-deploy will be skipped and the Workflow will exit. This is almost certainly a more desirable behavior for Production code.
If you’re currently shaking your fist and shouting the word DRY at me through your monitor, I feel you; there’s a lot of repetition in this code (but do remember that DRY is about repeated facts, not necessarily repeated code, and that premature abstraction is perhaps worse than repeated code).
Pedantic soapboxing aside, “How to set up the Runner for SDF” is definitely a repeated fact in our current configuration. To eliminate those repeated steps, we can extract the installation steps into our own custom Action which GitHub calls a composite action. The full reference documentation can be found here.
Composite actions are defined in yet another YAML file named action.yml. This file could exist in the same repository or a separate one; for simplicity in this article, we’ll create our action in the same repository.
While the file must be named action.yml, it can live anywhere in our repository. For that reason, I think it makes sense to make a new actions folder under our existing .github/ directory as a sibling to our workflows directory. To differentiate this action.yml from any other custom actions we might want in this repository, let’s create it under .github/actions/sdf-install/:
In the new action.yml, we can add the initial configuration for our composite action:
Before we implement the steps, we need to examine them for any dynamic data they require. Most of the Steps are static, but in order to correctly authenticate, we need a NetSuite Account ID, Token ID, and Token Secret. Let’s add these values as parameters in our action so that we can pass in the requisite data.
The parameters for an Action are specified with the inputs property:
With our inputs in place, we can extract the repeated installation steps into the steps structure, then replace the old environment variable references with references to our new inputs:
Notice that the checkout step is missing from our implementation. This is because the Action lives in the repository, so we can’t perform the Action without first checking out the repository. Thus, we’ll still have to perform the checkout step from each Job.
Back in sdf-validate.yml, we’re ready to replace the repeated installation steps with a single call to our new custom Action. In each of the three Jobs, our steps can now start like so:
We invoke Actions with the uses command. Within a uses command, inputs are specified using the with structure. Here we pass in the environment variables and secrets that we were previously specifying directly in our authentication Step.
Triggering our Workflow again, we should expect to see exactly the same behavior as before, but now with much less repeated configuration.
For those of you embarking on this CI/CD journey with me, and for all NetSuite developers generally, I sincerely hope you have access to at least one non-Production account for learning and testing, though I know that’s not always the case. While the functionality of our pipeline is filling out nicely, it can only operate on a single, hard-coded environment. To change the pipeline from Sandbox to Production or back, you’d currently have to push a code change in the configuration file; that kind of manual interaction is the opposite of what we want from our automation pipeline.
Luckily for us, the environment property of a Job accepts not only names but expressions as well. This means we can dynamically select an Environment for a Job based on conditions or values set in the pipeline.
I prefer to follow a feature-branching strategy in my SuiteScript repositories, so ongoing development is done in feature branches while main is considered the stable, Production-ready code. Using that information, I can conditionally select which Environment my Jobs should use based on which branch has changed:
The branch name which triggered the Workflow is available in the github context’s ref_name property:
In practice, you probably don’t want to continuously/automatically deploy to a Sandbox or Production account, unless you are a solo developer. If a team of developers is sharing the same account and working in the same repository which deploys every feature branch push, they’d constantly be overwriting each others’ changes.
You might, however, want to introduce a manual approval step into your pipeline to allow a gatekeeper to decide whether a build gets deployed or not. We can do so via the Required Approvers setting on an Environment.
By checking the Required reviewers box and specifying appropriate users in an Environment’s settings, GitHub will pause each Job that targets this Environment and wait for manual approval from the listed users. It will notify all approvers that a build is pending their review, and approvers can then jump into GitHub and provide their approval or rejection of a build.
For me, the behavior of this approval isn’t quite what I want as it will request approval on every Job within the Workflow. I’d prefer to incorporate an approval as a Step within a Job or Workflow instead (this is actually how CircleCI, a “competitor” of GitHub Actions, handles this process).
There is a third-party Action that purports to solve this problem, but it leverages the repository’s Issues to provide approvals, and that’s also not ideal for me. If you’re curious, I leave the investigation and setup of this Action to you as an exercise.
At this point, we have a strong and flexible foundation for automating the testing, validation, and deployment of our SuiteScript code. You can find this complete configuration in the Part 3 Release of my GitHub repository.
From here, I hope you’ve seen enough that you feel comfortable and inspired to add and adapt this Workflow to your needs, and I hope it makes delivering your SuiteScript easier, faster, and more enjoyable.