Brad Tilton

9 minute read

The Orlando and Paris releases have brought many new capabilities to the Now Platform allowing developers to implement their own Continuous Improvement and Continuous Delivery (CI/CD) pipelines to accelerate Now Platform development. Those include selective commits, editing outside of Studio, MID server support for the Source Control integration, global app support for Source Control, and APIs and IntegrationHub Spoke subflows and actions that allow developers to automate testing and deployment.

In addition to automating deployment pipelines inside ServiceNow, one of the things we’ve heard from developers is that many of them want to use their preferred DevOps tools to manage their ServiceNow CI/CD processes. Because of that ask we have announced four new integrations with market-leading CI/CD toolsets in a blog post on the ServiceNow Blog.

In this Developer blog post we’ll introduce the newly released ServiceNow CI/CD GitHub Actions and look at how to use them with your instance stack.

About GitHub Actions

Before jumping into the ServiceNow specific actions it is helpful to understand the core concepts. This is explained very well in the Introduction to GitHub Actions documentation, but I’ll pull out a couple of things here.

In GitHub, an event can automatically triggers a workflow. A workflow is a YAML file that contains jobs. A job contains one or more steps which control the order in which actions run. If that seems confusing I recommend going through the above linked doc that breaks everything down with some diagrams.

GitHub Actions allow you to automate nearly any part of your software development process, including tasks within your CI/CD process, all directly from GitHub.

ServiceNow’s GitHub Actions

To start with, we’ve published seven actions to the GitHub Marketplace.

  • Apply Changes - Applies changes from a remote source control to a specified local application.
  • Install App - Installs the specified application from the application repository onto the local instance.
  • Publish App - Publishes the specified application and all of its artifacts to the application repository.
  • Rollback App - Initiate a rollback of a specified application to a specified version if installation fails.
  • Run ATF Test Suite - Start a specified automated test suite.
  • Activate Plugin - Activate a desired plugin on your ServiceNow instance.
  • Rollback Plugin - Rollback a desired plugin on ServiceNow instance.

You can find links to the seven actions and links to their respective repos in the ServiceNow/sncicd_githubworkflow repo. We have links to the specific repos because they will rely on the open-source community to help drive fixes and feature enhancements via Issues. More information on that can be found in the repo.

How to Setup a CI/CD Pipeline using Github Actions

Now that you know about GitHub Actions and which actions are available to manage Now Platform development, let’s take a look at setting up and testing a CI/CD pipeline. The following video will show you how to create an app, link it to a GitHub repo, setup your pipeline using GitHub Actions, and then test your pipeline.

Setup

Note that you will not be able to follow along in a PDI, you’ll need a stack of instances that can access your company’s internal app repo.

  1. [Video Timestamp 1:13] Create your scoped or global application in your ServiceNow development instance and link it to an empty gGitHub repository.

  2. [3:04] In your GitHub repository, create a workflow and paste in the pipeline template we’ve provided in the ServiceNow/sncicd_githubworkflow repo.

    Before moving on, let’s take a closer look at what is happening in that pipeline template.

    name: ServiceNow GitHub Actions Demo
    
    on:
        pull_request:
        push:
            branches:
                - master
    

    In addition to the name, this is where you define the trigger through the on property. In this case the workflow is going to run on any pull request or a push to the master branch.

    There are three separate jobs defined: build, test, and deployprod. Let’s look at each individually.

    jobs:
        build:
            # Purpose of this job is to Apply Remote Changes for the branch triggering
            # the pipeline build to the Dev instance, then publish the application to
            # app repo using the template versioning format.
            name: Publish from Dev
            runs-on: ubuntu-latest
            # Below line can be used to set conditionals for modifying your pipeline as needed.
            # if: ${{ github.event_name == 'pull_request'}}
                
            steps:
                - name: ServiceNow CI/CD Apply Changes
                    uses: ServiceNow/sncicd-apply-changes@1.0.0
                    env:
                        snowUsername: ${{ secrets.SN_USERNAME }}
                        snowPassword: ${{ secrets.SN_PASSWORD }}
                        snowSourceInstance: ${{ secrets.SN_DEV_INSTANCE }}
                        appSysID: ${{ secrets.SN_APP_SYSID }}
    
                - name: ServiceNow CI/CD Publish App
                    id: publish_app
                    uses: ServiceNow/sncicd-publish-app@1.0.0
                    with:
                    versionTemplate: 2.4
                    versionFormat: template
                    env:
                        snowUsername: ${{ secrets.SN_USERNAME }}
                        snowPassword: ${{ secrets.SN_PASSWORD }}
                        snowSourceInstance: ${{ secrets.SN_DEV_INSTANCE }}
                        appSysID: ${{ secrets.SN_APP_SYSID }}
                    
            # This is required to pass the version number output from Publish App 
            # to the input for Install App in the next job! This is because the jobs 
            # run on different Linux instances, so without this Install App won't know
            # what to install.
            outputs:
                publishversion: ${{ steps.version.outputs.publishversion }}
    

    You can see here that the build job is using two of the ServiceNow GitHub actions and also referencing the secrets that that you’ll setup. It first does an apply changes where it pulls down the latest changes to the feature branch, and then it publishes the feature branch version of the app to the internal app repo.

        test:
            # Purpose of this job is to Install App from the app repo for the version 
            # published in the build job to a Test instance, then run an ATF Test Suite 
            # associated with the app. If Test Suite fails, the app should be Rolled Back 
            # to clean up the persistent Test environment. 
            needs: build
            name: Run ATF in Test
            runs-on: ubuntu-latest
            # Below line can be used to set conditionals for modifying your pipeline as needed.
            # if: ${{ github.event_name == 'pull_request'}}
                
            steps:
    
            - name: ServiceNow CI/CD Install App
                id: install_app
                uses: ServiceNow/sncicd-install-app@1.0.0
                with:
                    version: ${{ needs.build.outputs.publishversion }}
                env:
                    snowUsername: ${{ secrets.SN_USERNAME }}
                    snowPassword: ${{ secrets.SN_PASSWORD }}
                    snowInstallInstance: ${{ secrets.SN_TEST_INSTANCE }}
                    appSysID: ${{ secrets.SN_APP_SYSID }}
    
            - name: ServiceNow CI/CD Run ATF Test Suite
                uses: ServiceNow/sncicd-tests-run@1.0.0
                with:
                    testSuiteSysId: ${{ secrets.SN_ATFTESTSUITE_SYSID }}
                env:
                    snowUsername: ${{ secrets.SN_USERNAME }}
                    snowPassword: ${{ secrets.SN_PASSWORD }}
                    snowInstallInstance: ${{ secrets.SN_TEST_INSTANCE }}
    
            - name: ServiceNow CI/CD Rollback App
                if: ${{ failure() && steps.install_app.outputs.rollbackVersion }}
                uses: ServiceNow/sncicd-rollback-app@1.0.0
                with:
                version: ${{steps.install_app.outputs.rollbackVersion}}
                env:
                    snowUsername: ${{ secrets.SN_USERNAME }}
                    snowPassword: ${{ secrets.SN_PASSWORD }}
                    snowInstallInstance: ${{ secrets.SN_TEST_INSTANCE }}
                    appSysID: ${{ secrets.SN_APP_SYSID }}
    
        # This is required to pass the version number output from Publish App 
        # to the input for Install App in the next job! This is because the jobs 
        # run on different Linux instances, so without this Install App won't know
        # what to install.
        outputs:
            publishversion: ${{ steps.version.outputs.publishversion }}
    

    In the test job the first action is installing the app from the app repo into the test instance and then it’s running the ATF test suite specified in the secrets section. The third step is a Rollback App action, and will rollback the app install in the test instance if the ATF action failed.

        deployprod:
            # Purpose of this job is to Install App to a Prod instance. This should only 
            # trigger if the feature branch has been merged to master after a successfully 
            # completed pull request, hence the conditional for push to master. In other words,
            # the first two jobs run on CI, then all three jobs run on CD. 
            needs: test
            name: Deploy to Prod
            runs-on: ubuntu-latest
            if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
            steps:
                
            - name: ServiceNow CI/CD Install App
                id: install_app_prod
                uses: ServiceNow/sncicd-install-app@1.0.0
                with:
                    version: ${{ needs.test.outputs.publishversion }}
                env:
                    snowUsername: ${{ secrets.SN_USERNAME }}
                    snowPassword: ${{ secrets.SN_PASSWORD }}
                    snowInstallInstance: ${{ secrets.SN_PROD_INSTANCE }}
                    appSysID: ${{ secrets.SN_APP_SYSID }}
    

    The last job is the deployprod job that does just what it’s named and deploys the app to the production instance. You can see that this job has an if statement where it is only running when you are pushing to the master branch. The only step in this job is installing the app from the internal app repo to the production instance specified in the secrets.

    Youbll notice that the build and test jobs will run after a pull request is started to merge the feature branch into the master branch. This is a CI build validating the feature branch app build on a test instance via an ATF Test Suite. When the CI build passes and that pull request is completed, the feature branch is merged, triggering the workflow again with a CD build where all three jobs will run, but this time they will build, test, and deploy the master branch app build.

  3. [5:09] Now you’ll need to setup your GitHub secrets. Secrets in GitHub are basically encrypted environment variables that can be used from GitHub Actions workflows. You can think of these in the same way that you think of system properties in ServiceNow. You’ll need to setup secrets for things like your authentication details, instance URLs, app sys_id, etc.

Now that you have created the app, added your GitHub Actions workflow, and setup your secrets, you are ready to test your workflow.

Testing

Now it’s time to test this GitHub Action workflow created in the previous build section.

  1. [5:55] Open Studio in your development instance and pull down the latest changes from the repo, then create a new feature branch for your development work.

  2. [6:22] Create a script include (or any application file).

  3. [6:54] In Studio, apply remote changes, apply your stashed changes, and then commit those changes to your feature branch.

  4. [8:05] Open up your GitHub repo in your browser and create a Pull Request. You’ll be able to see the details on the workflow steps as they’re executing.

    In this part of the workflow you are pulling down the latest changes to the feature branch to the development instance, publishing that version of the app to the internal repo, installing the app in your test instance, and running the specified ATF test. If the test fails, the app install in your test instance will be rolled back.

  5. [10:04] Before you merge the pull request you’ll need to switch your branch back to the master branch in Studio.

    This is because “apply remote changes” works only on the branch currently active on the instance, and your CD build will trigger immediately after the merge pushes new commits to your master branch.

  6. [10:38] Now you’re ready to merge the pull request in GitHub.

    When you do this, the workflow will be kicked off again automatically, but this time it’s running against the master branch instead of the feature branch it ran against earlier. Since it’s now a push against the master branch it will run the third deployprod job, which will install the app on the production instance.

Conclusion

You can see how easy it is to configure your first ServiceNow development CI/CD pipeline using GitHub Actions. All you did was copy in the pipeline template and create a set of secrets in the GitHub repo associated with the app you were developing against.

Remember, you can find the repo with links to the GitHub Actions in the Marketplace and links to the individual GitHub repos for the actions at the ServiceNow/sncicd_githubworkflow repo. They are open-source and community driven so you are more than welcome to take a look at the Issues and contribute. For more information on all of our external dev pipeline tooling visit the pluginsAndIntegrations page.


Comments