Chained Builds with Codeship API v2

Written by: Kelly Andrews
4 min read
Stay connected

UPDATE: As of January 10th, 2018, we released a Go client for Codeship’s API. To learn more, read the documentation article.

The Codeship API v2 general availability release happened earlier this week, and I thought it would be useful to try out one of the main use cases listed in the feature blog post: triggered builds.

Overview

In your project, it can become necessary to trigger builds without a code commit. Typical scenarios involve some module that is included in multiple projects like an NPM package or possibly a full service in a microservice application. If a module is updated, your team may want to also test other projects to validate that nothing has broken the entire system, and potentially deploy the latest version of that module.

This is where the latest version of the API will help us out. I will cover how to set up a quick webhook using Webtask.io that will listen for notifications and kickoff any number of builds.

Project Setup

In order to keep things easy, the repos themselves are simply readme files. I named these repos project-1, project-2, and module-a.

For this example, create all of the projects that are created in Codeship by connecting the repo as a basic project and leaving everything else empty. In other words, there are not any testing or deployment steps at all.

In a real scenario, the steps themselves can be virtually anything, and I want to focus on what happens in the middle -- after the module is successfully built and before the projects start a build.

Create the Webhook

I have a deep appreciation for anything that is serverless. Webtask.io is a favorite of mine to use for examples because I can use it for free and it has a quick setup. Once you sign up, simply create a new Webtask and start coding.

[caption id="attachment_5877" align="aligncenter" width="540"]

Create a new Webtask Function[/caption]

Create a new Webtask Function, and you can create it as empty. Webtask also offers templates for other common tasks, but we are starting from scratch.

I am using the node-fetch module here. We can add that by clicking the wrench icon and selecting NPM Modules in the dropdown. The left pane will open, and you can click Add Module. Type in node-fetch and select the matching result. Once you do this, you can now use that module in the Webtask directly.

[caption id="attachment_5878" align="aligncenter" width="496"]

Adding an NPM module[/caption]

There are also some secrets you will want to set up to match the code as well. This particular Webtask uses codeship_user, codeship_pw for the authentication and codeship_org_id.

You will want to authenticate your user using cURL or Postman first, to get your organization's ID. For more details about the auth route, you can see the documentation.

curl --request POST \
  --url http://api.codeship.com/v2/auth \
  --header 'authorization: Basic dGVzdC11c2VyOnRoaXNpc3RvdGFsbHlmYWtl' \
  --header 'content-type: text/plain'

[caption id="attachment_5879" align="aligncenter" width="513"]

Adding a secret[/caption] Here is the full code you can copy and paste into the Webtask.

'use latest';
import fetch from 'node-fetch';
const chained_projects = [
  'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
  'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
]
let projects_url, auth;
module.exports = (ctx, cb) => {
  const { codeship_org_id, codeship_user, codeship_pw } = ctx.secrets;
  projects_url = `http://api.codeship.com/v2/organizations/${codeship_org_id}/projects`;
  auth = new Buffer(`${codeship_user}:${codeship_pw}`).toString('base64');
  for (var project in chained_projects) {
    start_build(chained_projects[project]);
  }
  cb(null, ctx.body);
};
function auth_codeship() {
  const options = {
    method: 'POST',
    headers: {
      Authorization: `Basic ${auth}`,
    },
  };
  return fetch('http://api.codeship.com/v2/auth', options)
    .then(res => res.json())
    .then(json => json.access_token);
}
function start_build(project_id) {
    auth_codeship().then(token => {
    const options = {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-type': 'application/json',
      },
      body: JSON.stringify({
         "ref": "heads/master"
      }),
    };
    fetch(`${projects_url}/${project_id}/builds`, options)
      .then(res => res.json())
      .then(json => {
        console.log(json);
      });
  });
}

I have my project UUIDs from the projects API response for the examples I created earlier, and I add those to the chained_projects array. I can then loop through the array and use my start_build function to start up a build on Codeship using the create build API.

At this point, you can test the webhook and see if the projects will start building. I would recommend setting up some fake projects to test, since the code above will restart the last build to the controller branch.

Create the Notifications

Once the webhook is up and running, the last task is to call the Webtask when the module is done building. The easiest way to do this would be to use the Codeship notifications.

Navigate to the module project example you created earlier and go to Project Settings, then click Notifications, and finally add a Webhook notification. We only want to get notified on successful builds and when it's on the controller branch. See the image below:

[caption id="attachment_5880" align="aligncenter" width="1285"]

Adding a webhook notification[/caption]

Now when the module is successfully built, your projects that consume the module will start new builds to validate that the module works within their scope.

Conclusion

Hopefully this quick example of how to use the Codeship API to chain builds together gets you thinking of new ways to enhance your build processes. If you have any questions or comments, I would love to hear from you as well.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.