RStudio Connect Deployments with GitHub Webhooks and Jenkins

TL;DR: New content management Connect server APIs are easy to integrate with programmatic deployment workflows.

Have you heard!? RStudio Connect 1.7.0 has support for programmatic deployment in the RStudio Connect Server API. These new APIs let your deployment engineers craft custom deployment workflows like these:

Image for post
Image for post

This article demonstrates programmatic deployment of a Shiny application with GitHub webhooks and a Jenkins Freestyle project.

What are we trying to build?

I have a data product (in this case a shiny application) deployed to my RStudio Connect server. I also have a GitHub repository for the application where I’ve version controlled the app code. I want to link and automate the application update process with my GitHub workflow, i.e. every time I push a code change to GitHub, I’d like the deployed application on Connect to automatically be updated with those changes.

Image for post
Image for post
Basic Build Plan

This workflow assumes that the content has already been deployed to my Connect Server at least once. The initial deployment could be achieved programmatically or through traditional IDE push-button / rsconnect deployment methods. The content management API for RStudio Connect can be leveraged to perform the initial bundle upload programmatically.

To read more about the content management APIs and view existing recipes, please see the following resources:

After reviewing the API documentation and example scripts, flesh out your plan to include actionable steps and tools. My updated diagram shows each process and the required resources for defining functional automation:

Image for post
Image for post
Actual Build Plan

Note: I started this project with a brand new, clean Jenkins Server. I use Ansible to create (and tear down) small Jenkins servers that live for the duration of my experiments. This article will not cover the basics of installing and configuring a Jenkins server.

Development and Git Branching

Application development occurs in the RStudio IDE. I plan to create a git branching strategy so that new changes can be kept separate from the master branch and reviewed before merging. The GitHub repository I created to keep the application code can be viewed here:

GitHub repository for the Shiny application
- deployment-bundle: app.R, manifest.json
- README.md

This repository contains a README file (not required) and a single directory with all the application code (in this case only an app.R file) as well as the manifest file which can be generated with the rsconnect package in the RStudio IDE: rsconnect::rsconnect::writeManifest()

GitHub Webhooks

The next step of GitHub set up is to create a Webhook so that the Jenkins server can be notified of all new changes to Master.

In the GitHub repository, navigate to the Settings page, then select Webhooks from the left sidebar. Add a new webhook to see the management form as shown here:

Image for post
Image for post
Create a new webhook for Jenkins

For the Payload URL field, provide the URL of your Jenkins server with /github-webhook/ appended to it. These are the selections I set for the webhook:

Payload URL: http://[EXAMPLE-AWS-INSTANCE]/github-webhook/
Content type: application/json
Secret: [blank] — I did not use this
Event triggers: Just the push event
Active: Check

Jenkins GitHub Integration Plugin

Now that the webhook is in place, the next step is to configure the receiving end. Jenkins needs the GitHub Integration plugin to receive POST payloads coming from GitHub every time the push event triggers.

Add the GitHub plugin to Jenkins:

  • Manage Jenkins > Manage Plugins
Image for post
Image for post
Manage Jenkins Plugins

Check the Installed tab to see if the GitHub Integration Plugin already exists. If not, search for it in the Available tab, download and install.

Docker in Jenkins

In order to streamline the deployment build process for this project, I’ve chosen to use Docker image provided in the programmatic deployment example repo provided here: rstudio/connect-api-deploy-shiny.

There are many ways to incorporate the use of Docker containers into Jenkins projects. Rather than leverage an eternal container registry and a Jenkins-Docker plugin, I’ll show quick-and-dirty way, invoking it directly with shell commands.

Note: My Jenkins server is built with the Docker service installed, so this will work for my project, but it might not work for yours. Take the time to investigate what Docker integrations exist and are considered best practices if you are working on a shared or pre-existing Jenkins installation.

In a second GitHub repository, I’ve version controlled all the pieces of the deployment environment as well as the upload-and-deploy.sh script that will be used to interact with the RStudio Connect content management API. This repository is separate from the Shiny application code repo so that I can have a singular, centralized location for keeping just these pieces of the process.

GitHub repository for the dockerfile and deployment scripts:
- docker: Dockerfile
- upload-and-deploy.sh (modified from rstudio/connect-api-deploy-shiny)
- README.md

Create a Jenkins Project

All the parts are in place, so finally it’s time to put everything together in Jenkins.

Start a New Item > Freestyle Project

  • Give your project a name (e.g. “basic-app-deploy”)
Image for post
Image for post
Start a Freestyle Project

Sidebar: Why Jenkins Freestyle?

If there were a crawl-walk-run strategy for working with Jenkins, Freestyle projects might be the crawl step. If you’re already familiar with Jenkins, you might be more interested in setting up a pipeline project or using a Jenkinsfile to structure the workflow.

Pros and Cons of Jenkins Freestyle:

Pro: New to Jenkins ?— low learning curve
Pro: Nice way to learn the Jenkins web interface
Pro: Quick way to accomplish simple jobs (this is not a complex build)

Con: Way too much clicking through web forms
Con: Job is not defined as code

Navigate the Freestyle Project Webform

Once you have a new project set up, step through the freestyle webform complete the configuration:

General

Source Code Management

Build Triggers

  • Check: GitHub hook trigger for GITScm polling

Build Environment > Bindings

Programmatic deployment requires an RStudio Connect API key. Generate an API key through the Connect user interface:

Image for post
Image for post
RStudio Connect API Keys

Add Credentials: Save the API key as a Secret Text in Jenkins Credentials Provider:

You can expose secret texts to the Build Environment through the Bindings option:

  • Check: Use secret texts or files
    Secret text:
    - Variable: PUBLISHER_KEY (choose a name)
Image for post
Image for post
Save the API key as a Secret Text in Jenkins Credentials Provider

Build

The build pane allows for many different types of task selections. For simplicity, I chose the Execute Shell Commands option. I created three blocks of Shell Command build tasks, but the separation was only for readability:

Execute Shell Block 1: Read in the Dockerfile and deployment shell script from GitHub

rm -rf prog-deploy-jenkins
git clone https://github.com/kellobri/prog-deploy-jenkins.git
stat prog-deploy-jenkins/docker/Dockerfile
chmod 755 prog-deploy-jenkins/upload-and-deploy.sh

Execute Shell Block 2: Build the Docker image

cd prog-deploy-jenkins/
docker build -t rstudio-connect-deployer:latest docker

Execute Shell Block 3: Run the Docker container and deployment script

docker run --rm \
--privileged=true \
-e CONNECT_SERVER="http://ec2-52-90-255-153.compute-1.amazonaws.com:3939/" \
-e CONNECT_API_KEY=$PUBLISHER_KEY \
-v $(pwd):/content \
-w /content \
rstudio-connect-deployer:latest \
/content/prog-deploy-jenkins/upload-and-deploy.sh 5c276b83-2eeb-427b-95a6-ac8915e22bfd /content/deployment-bundle

In this block, I reference the PUBLISHER_KEY credential created in the Build Environment step earlier.

Image for post
Image for post
Content GUID lookup

I have also hard-coded two additional important pieces of information: the CONNECT_SERVER address, and the application GUID. You could easily create a secret text credential for the server address like we made for the the API key. The application GUID is an identifying piece of information that you’ll have to look up from the RStudio Connect User Interface.

The app GUID is listed at the bottom of the Info settings tab of the deployed content on RStudio Connect.

Project Finishing Touches:

  • Save your Jenkins freestyle project
Demo of a Successful Test

Useful Jenkins Debugging Areas

From the Jenkins dashboard, click on your project. Here you can go back to the webform and change something by clicking the ‘Configure’ link. To see details about the last build, click on that build link; from here you can access the console output for the build — this is usually the first place I go when a build fails.

Image for post
Image for post
Console Output for Jenkins Debugging

Also great for iteration and debugging: You can always schedule and run build tests directly from Jenkins without pushing random code changes to GitHub.

Success — What’s Next?

Congrats! Here are some places to explore next:

What if I need to do this for five more shiny apps?

Use this working freestyle project as a template for a new project!

From the Jenkins Dashboard, Select: New Item > Name the project > Then scroll to the bottom of the project type selection options and use auto-complete to find the project you’d like to copy from:

Image for post
Image for post
Use your first project as a template for others

Great — But what if I need to do this for 100 more shiny apps?

Remember that crawl-walk-run strategy that I mentioned earlier? If you need to put CI/CD in place for 100 shiny applications, you’re probably going to want to consider some of the other methods for interacting with Jenkins.

Freestyle projects are a great learning tool — and can be helpful for getting small projects off the ground quickly. But I wouldn’t recommend using them long term unless clicking around in webforms is your favorite thing ever.

If you’re looking to do large-scale programmatic deployments with Jenkins, I recommend moving toward a workflow structured on pipeline projects and Jenkinsfiles.

Key Resources in this Article:

RStudio Community is a great place to start conversations and share your ideas about how to grow and adapt these workflows. Please join me there: https://community.rstudio.com/c/r-admin

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store