Comparing a local file with a workspace file with C# and TFS

The situation is simple:

  • we need to send messages to another system
  • the developers of the other system need documentation on the layout of these messages
  • this is a company-specific protocol (no JSON or anything standard, because we're talking to old Fortran machines here)
  • naturally, the documentation is made in Word filesTaking an example from a session I saw at ngEurope, I decided we might be better off auto-generating this documentation. Keeping Word files in sync with the evolving code is a tedious, manual process, not to mention that the Word files are never in sync 10 years down the road.

And as the code is the single point of truth, I started on automating the process. I hate repeating manual things. It's boring, allows for manual error (I remember updating a production SQL database instead of the beta database!), and needs to be taught to newcomers time and again.

So:

After having written code to generate the documentation (too specific to put here), I needed a way of having the build automatically add the new file to the pending changes, or if nothing had changed, undo the checkout (sadly, I'm on TFS; git would not have this problem).

So this is how you can compare a local file with the server version of the file:

private bool HasFileChanged(string file, TfsTeamProjectCollection server, Workspace workspace)  
{
    string diff;

    var versionControlServer = server.GetService<VersionControlServer>();

    var serverPath = workspace.GetServerItemForLocalItem(file);
    var serverVersion = new DiffItemVersionedFile(versionControlServer, serverPath, VersionSpec.Latest);
    var localVersion = new DiffItemLocalFile(file, Encoding.UTF8.CodePage, DateTime.Now, false);

    using (var stream = new MemoryStream())
    using (var writer = new StreamWriter(stream))
    {
        var diffOptions = new DiffOptions
        {
            Flags = DiffOptionFlags.EnablePreambleHandling,
            OutputType = DiffOutputType.Unified,
            TargetEncoding = Encoding.UTF8,
            SourceEncoding = Encoding.UTF8,
            StreamWriter = writer
        };

        Difference.DiffFiles(versionControlServer, serverVersion, localVersion, diffOptions, serverPath, true);
        writer.Flush();

        diff = Encoding.UTF8.GetString(stream.ToArray());
    }

    return diff != "";
}
The server and workspace variables can be made like this:
var workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(file);  
var server = new TfsTeamProjectCollection(workspaceInfo.ServerUri);  
var workspace = workspaceInfo.GetWorkspace(server);