GitHub Automation

Forbes Lindesay

slides.forbesl.co.uk

esdicuss.org

Before

After

Version 0

PIPERMAILAT BUILDHTML
  • Slow to see changes to rendering logic
  • Fast to load pages
  • One post per page
  • No support for editing

Version 1

PIPERMAILPER REQHTML
  • Fast to see changes to rendering logic
  • Slow to load pages
  • One post per page
  • No support for editing

A website built on GitHub

  • Free, unlimited storage
  • Built in support for editing and moderation

Version 2

PIPERMAILONCEGitHubONCEDatabasePER REQPER REQHTML
  • Fast to see changes to rendering logic
  • Slow to load pages
  • Many posts per page
  • Great support for editing

Git command line

  • Simple to get started
  • Requires installation
  • Limited functionality
  • Requires having everything locally to make changes

GitHub API

  • Difficult to make multi-file commits
  • No installation required
  • Full functionality of GitHub

Version 3

PIPERMAILONCEDatabasePER REQHTML
  • Fast to see changes to rendering logic
  • Fast to load pages
  • Many posts per page
  • Support for editing

Using the GitHub API

REST API

https://developer.github.com

https://api.github.com

Some requests return "404 Not Found" when they should return "403 Forbidden"

Authentication - OAuth2

var github = require('github-basic');
var client = github({
  version: 3,
  auth: '<MY-OAUTH-TOKEN>',
  sync: true
});
client.get(path, query)
client.delete(path, query)
client.post(path, query)
client.patch(path, query)
client.put(path, query)

Making a Commit

function commit(owner, repo, branch, commit, opts) {
  var message = commit.message;
  var updates = commit.updates;
  // => [{path: 'string', content: 'string'}, ...]
  var force = opts.force || false;

  var head = client.get('/repos/:owner/:repo/git/refs/:ref',
    {owner: owner, repo: repo, ref: 'heads/' + branch});
  var shaLatestCommit = head.object.sha;

  var commit = client.get('/repos/:owner/:repo/git/commits/:sha',
    {owner: owner, repo: repo, sha: shaLatestCommit});
  var shaBaseTree = commit.tree.sha;

  var newTree = client.post('/repos/:owner/:repo/git/trees',
    {owner: owner, repo: repo, tree: updates, base_tree: shaBaseTree});
  var shaNewTree = newTree.sha;

  var newCommit = client.post('/repos/:owner/:repo/git/commits',
    {owner: owner, repo: repo, message: message, tree: shaNewTree, parents: [shaLatestCommit]});
  var shaNewCommit = newCommit.sha;

  client.patch('/repos/:owner/:repo/git/refs/:ref',
    {owner: owner, repo: repo, ref: 'heads/' + branch, sha: shaNewCommit, force: force});
}

Or you can just use client.commit

Demo Time

Jade

Jade

before

!!! 5

after

doctype html

Several angry people: https://github.com/visionmedia/jade/pull/1374

Jade - fixup-doctype.js

module.exports = function (text) {
  return text
    .replace(/^\s*\!\!\!\n/g, '!!! 5\n')
    .replace(/^\s*\!\!\! ([a-zA-Z0-9]+\s*\n)/g, 'doctype $1')
    .replace(/^\s*doctype 5(\s*\n)/g, 'doctype html$1');
};

Jade - fix repo

var github = require('github-basic');
var GitHubBot = require('github-bot');
var fixDoctype = require('./fix-doctype.js');

var GITHUB_TOKEN = '<GITHUB-TOKEN>';

var client = github({version: 3, auth: GITHUB_TOKEN, sync: true});
var bot = new GitHubBot(GITHUB_TOKEN, 'store', processRepo);
bot.run('visionmedia', 'jade').done();

var TITLE = 'Change doctype from using !!! 5' +
            ' style to doctype html';
var BODY = 'Jade has removed support for `!!!`' +
           ' as a shorthand for writing `doctype`' +
           ' and `5` as a shorthand for writing' +
           ' `html`.  This automated pull request' +
           ' updates the doctypes in your repository.';

function processRepo(owner, repo, branch, files) {
  // files is an array of
  // {
  //   path: 'path/to/file.js',
  //   name: 'file.js',
  //   data: Buffer(body of file),
  //   text: 'body of file'
  // }
  files = files.filter(function (file) {
    return /\.jade$/.test(file.name);
  });
  if (files.length === 0) return;
  var results = files.map(function (file) {
    return {
      path: file.path,
      content: fixDoctype(file.text)
    };
  });
  results = results.filter(function (result, index) {
    return result.content !== files[index].text;
  });
  if (results.length === 0) return;
  client.fork(owner, repo, {organization: 'jade-bot-1'});
  client.branch('jade-bot-1', repo, branch, 'fix-doctype');
  client.commit('jade-bot-1', repo, {
    branch: 'fix-doctype',
    message: 'Fix use of deprecated jade features and update jade',
    updates: results
  });
  var res = client.pull(
    {user: 'jade-bot-1', repo: repo,branch: 'fix-doctype'},
    {user: owner, repo: repo, branch: branch},
    {title: TITLE, body: BODY});
  console.log(res._links.html.href);
}

Regenerator Runtime

function* integers(max, step) {
  var i;
  while (true) {
    i++;
    yield i;
  }
}
var marked0$0 = [integers].map(regeneratorRuntime.mark);
function integers(max, step) {
  var i;

  return regeneratorRuntime.wrap(function integers$(context$1$0) {
    while (1) switch (context$1$0.prev = context$1$0.next) {
    case 0:
      if (!true) {
        context$1$0.next = 6;
        break;
      }

      i++;
      context$1$0.next = 4;
      return i;
    case 4:
      context$1$0.next = 0;
      break;
    case 6:
    case "end":
      return context$1$0.stop();
    }
  }, marked0$0[0], this);
}
require('regenerator/runtime');
var regeneratorRuntime = require('regenerator-runtime-only');

How do I keep it up to date?

Write a bot!

Other Ideas

GitHub Real Names

https://github.com/ForbesLindesay/github-real-names

Open Source Report Card

Git Spective

HuBoard

Build More Bots

  • Fix deprecated features
  • Better issue trackers
  • Close issues that haven't been touched in years
  • Hunt for likely error such as undefined variables
  • Automatically patch security vulnerabilities
    (read from https://nodesecurity.io/ then submit pull requests to update versions)
  • Automatic version number management: peer dependencies

Join Me!

Forbes Lindesay

slides.forbesl.co.uk

Social Networks

Twitter: @ForbesLindesay

GitHub: @ForbesLindesay

Blog: www.forbeslindesay.co.uk

Open Source

Jade

Browserify Middleware

readable-email.org

brcdn.org

tempjs.org