A few months ago I developed utility to pull commits, files and numbers of changes from Github repositories. The utility has been working fine, but I decided to also go after repositories hosted on Bitbucket.

Both Github and Bitbucket provide RESTfull API. For this scenario Bitbucket APIs are harder to work with because unlike Github which provides the files in the given commit and changes in each file through object model returned by a resource (for example, commit object has file collection and file has stats), Bitbucket gives a link to unidif. Basiclly a block of text with numbers.

Therefore my first order of business was to parse out this unidiff which I outlined here.

With that out of the way getting churn isn't that difficult:

public class BitbucketProvider : IGitProvider  
    private readonly IBitbucketService _service;
    private readonly DiffParser _diffParser;

    public BitbucketProvider(IBitbucketService service)
        _service = service;
        _diffParser = new DiffParser();

    public List<Data.Commit> GetCommits(string repo, DateTime from, DateTime to)
        var commitsJson = _service.GetCommits(repo, "master");
        var pageCommits = JsonConvert.DeserializeObject<CommitHeader>(commitsJson);
        List<Commit> bitbucketCommits = pageCommits.Commits;

        while (!string.IsNullOrEmpty(pageCommits.NextPageUrl))
            commitsJson = _service.GetString(pageCommits.NextPageUrl);
            pageCommits = JsonConvert.DeserializeObject<CommitHeader>(commitsJson);

        // Since Bitbucket doesn't provide filter by date
        bitbucketCommits = bitbucketCommits.Where(w => w.Date >= from && w.Date <= to).Select(s => s).ToList();

        foreach (var commit in bitbucketCommits)
            var diffText = _service.GetDiff(commit.Urls.Diff.Value);
            commit.Files = _diffParser.Parse(diffText);

        List<Data.Commit> commits = Mapper.Map<List<Data.Commit>>(bitbucketCommits);
        return commits;

Bitbucket API doesn't provide date filter and also returns data in pages.

See full code here