Fetching code from Codeplex in Strider

Last time, I was able to get strider to recognize my branches in codeplex. However, it still won't fetch the code. Which is the whole point of this entire process!

For a Node project, the first thing that strider does is try to get a package.json file from the repo. Unfortunately, there is no good way to do this with either git or mercurial. And of course, there is no codeplex api to do so. Thankfully, strider allows us to specify that we don't support individual files via fastFile. We will also throw an error if getFile is called(in webapp.js):

fastFile: false,  
getFile: function (filename, ref, account, config, project, done) {  
  done(new Error('not implemented'));
}

Next, in worker.js, we need to implement two exports: init and fetch. Based on strider-github, init needs to return an object that also calls fetch, like so:

module.exports = {  
  init: function (dirs, account, config, job, done) {
    return done(null, {
      config: config,
      account: account,
      fetch: function (context, done) {
        module.exports.fetch(dirs.data, account, config, job, context, done);
      }
    });
  }
}

Implementing fetch should be pretty simple. I just need to use strider-git to fetch a git repo, and strider-hg (crap, when I started this series, I thought it existed, but now I can't find it...) hg for mercurial ones:

fetch: function(dest, account, config, job, context, done) {  
  if (config.type === 'git') {
    git.fetch(dest, config, job, context, done);      
  } else if (config.sourceType === 'mercurial') {
    hg.clone(config.sourceUrl, dest, {"-b": job.ref.branch}, done);
  }
}

Now, when I try to test... nothing. Well, crap. After some debugging, it turns out that Codeplex capitalizes git and mercurial. That is annoying, so I decided to alter the parseRepo function in webapp.js to make the sourceType lowercase:

function parseRepo(account, repo) {  
  return {
    id: account.name + '/' + repo.Name,
    name: account.name + '/' + repo.Name,
    display_name: repo.Title,
    display_url: repo.Url,
    group: repo.Role,
    'private': !repo.IsPublished,
    config: {
      sourceType: repo.SourceControl.ServerType.toLowerCase(),
      sourceUrl: repo.SourceControl.Url,
      repoName: repo.Name
    }
  }
}

Trying it again... And it fails. Because the config is missing an auth:

    config: {
      sourceType: repo.SourceControl.ServerType.toLowerCase(),
      sourceUrl: repo.SourceControl.Url,
      repoName: repo.Name,
      auth: {
        type: 'https'
      }
    }

Aaaand... Fail. No repo. Grrr. At this point, I just renamed everything to match the strider-github setup:

    config: {
      type: repo.SourceControl.ServerType.toLowerCase(),
      url: repo.SourceControl.Url,
      repo: repo.Name,
      auth: {
        type: 'https'
      }
    }

I obviously had to change the references everywhere else, also. After doing so, it worked! Well, for git repos anyway. Mercurial repos have an issue with the default branch. In git, it is master, where in mercurial it is default. Strider doesn't take this into account, so I had to:

var branch = job.ref.branch;  
if (branch === 'master') {  
  // hg's default branch is default, not master... Ideally this would be handled in the repo setup, but use this as a workaround
  branch = 'default';
}

One last problem for the mercurial side of things: it won't report progress to the strider output window. To solve this, I had to do a bit of extra work:

if (config.type === 'mercurial') {  
  var branch = job.ref.branch;
  if (branch === 'master') {
    // hg's default branch is default, not master... Ideally this would be handled in the repo setup, but use this as a workaround
    branch = 'default';
  }
  var start = new Date()
    , cmd = 'hg clone ' + config.url + ' . -b ' + branch;
  context.status('command.start', { command: cmd, time: start, plugin: context.plugin });
  hg.clone(config.url, dest, {"-b": branch}, function(err, output) {
    var end = new Date()
      , elapsed = end.getTime() - start.getTime();
    if (err) {
      context.out('hg error: ' + err.message);
    }

    if (output) {
      output.forEach(function(line) {
        context.out(line.body);
    });
  }

  context.status('command.done', {exitCode: 0, time: end, elapsed: elapsed});
    done(err, output);
  });
}

And with that, Strider can fetch code from Codeplex!

One last thing I've done, to make the plugin match the other strider plugins: I moved strider.json to package.json.

You can grab the code at github.

-Ah


View or Post Comments