RSCM - Ruby Source Control Management (0.4.2)

RSCM is to SCM what DBI/JDBC/ODBC are to databases - an SCM-independent API for accessing different SCMs. The high level features are roughly:

  • Check out a working copy (with possibility to specify branch/date/label)

  • Get revisions (changesets) (Emulated for non-transactional SCMs like CVS, ClearCase and StarTeam)

  • Get diffs

  • Add and commit files

  • Manipluate triggers

Although RSCM's main focus is operations on a working copy of an SCM repository, the API also allows some level of interaction with the SCM repository itself, like creating new repositories.

Download

RSCM is available as a RubyGem, and can be installed like this:

gem install rscm

(You may need administrator access to do this on a POSIX system). If you want the latest and greatest, you can get the sources:

Anonymous:

svn co svn://svn.damagecontrol.codehaus.org/damagecontrol/scm/trunk/rscm

Developers:

svn co svn+ssh://[email protected]/home/projects/damagecontrol/scm/trunk/rscm

Contributors

  • Aslak Hellesoy - All

  • Steven Baker - Monotone

  • Jon Tirsen - CVS, Subversion

  • Yogi Kulkarni - Perforce

Supported SCMs

In progress:

Planned:

Loads! All of them! How to add support for a new one is described further down in this file.

Related projects

built around RSCM and Ruby on Rails.

Sample usage

Here is an example of how to use RSCM to get a list of revisions (aka changesets) from a subversion repository:

require 'rscm'
scm = RSCM::Subversion.new("svn://some.server/some/path/trunk")
scm.default_options = {:stdout => "stdout.log", :stderr => "stderr.log"}
# What follows would look the same for any supported SCM
revisions = scm.revisions(Time.utc(2004, 11, 10, 12, 34, 22)) # For Subversion, you can also pass a revision number (int)
revisions.each do |revision|
  puts revision # or do something more funky with it
end

Using visitors

Although the Revisions and Revision classes support external iteration (with each as in the example above), they also support visitor traversal via their accept methods. A visitor must respond to the following methods:

def visit_revisions(revisions); end
def visit_revision(revision); end
def visit_file(revision_file); end

Future plans

Cross-SCM synchronisation

RSCM could be used as a tool to migrate files from one SCM to another (of a different type) while keeping the history. -Similar to cvs2svn or nautilus.homeip.net/~lele/projects/tailor/

RSCM could also be used as a continuous synchronisation service between SCMs. This can be very useful when you have to work with an SCM and you'd rather use a different one. RSCM could synchronise between the central SCM and one that you set up on your local machine.

Implementing support for a new SCM

We'd be happy to receive contributions for more SCMs. You can always file a JIRA issue (jira.codehaus.org/browse/DC) and hope for someone to implement it for you, or you can do it yourself. The rest of this file should get you started.

N.B. IF YOU START IMPLEMENTING A NEW RSCM PLUGIN, PLEASE SUBMIT YOUR CODE TO JIRA AT AN EARLY STAGE (BEFORE IT'S COMPLETE). THIS WAY IT'S EASIER FOR EXISTING DEVELOPERS TO PROVIDE TIPS AND HELP UNDERWAY.

Let's write an RSCM implementation for the imaginary SCM called Mooky. You should be able to use the same recipe for most SCMs.

Writing the API

Start by writing a test:

test/rscm/mooky/mooky_test.rb

By including GenericSCMTests your test will automatically include the acceptance test suite for RSCM. By doing this you'll actually follow a TDD approach for your new Mooky class - except that the tests are already written for you!

IMPORTANT NOTE: If your SCM doesn't provide an easy way to create new local repositories (such as with StarTeam) you're probably better off writing the tests from scratch and not include GenericSCMTests. Instead, just make sure you have an SCM repository set up somewhere and write tests to work against that repository. This way you won't be able to pass the generic acceptance test suite, and other people (like the RSCM dev team) will probably not be able to run the tests for it. -But it's better than nothing. We'll happily accept contributions that don't use the generic tests, although it would be best if they did.

OK, back to mooky. As you will see in a minute, the generic test suite will be of great help when developing the Mooky class. The tests will attempt to check in some sample files and call various methods on the mooky object to verify that it behaves correctly according to the RSCM API. (The sample files consist of some java sources, but you don't need Java installed. They're just files).

Let's implement the Mooky class. Take a look at.

lib/rscm/scm/mooky.rb

Try running Mooky's test:

rake test TEST=test/rscm/scm/mooky_test.rb

Whoops - we got some failures! It failed because our checkout method returned nothing (nil). Let'see if we can get the a little further by implementing this method.

The Mooky SCM happens to have a command line utility to perform a checkout. From the command line a checkout with mooky would be done like this:

cd somewhere
mooky checkout --repo mooky://some/where/else

Running this command will print the following to standard out:

checkout build.xml
checkout project.xml
checkout src/java/com/thoughtworks/damagecontrolled/Thingy.java
checkout src/test/com/thoughtworks/damagecontrolled/ThingyTestCase.java

What we need to do is to execute these commands from Ruby. We also need to parse the output from the mooky command to determine the files that were checked out, so that we can return an array with the file names of the checked out files (the method should also yield each file name as the execution proceeds).

Once your checkout command works okay, the test will get you a little further. Just keep on going until all tests pass.

NOTE: If the SCM doesn't have a command line utility (unlikely) or a 3rd party Ruby API, but instead provides libraries (perhaps in C), then you should consider writing a Ruby C extension instead.

If the SCM has a Java interface, you can take the same approach as for StarTeam. There are Java classes for Revisions that allow easy interaction between Ruby and Java over YAML. You can reuse these classes for other Java based SCMs (if there are any, I don't know).

Web interface (DamageControl only)

DamageControl automatically detects new SCM classes in RSCM and generates a default web interface.

Building RSCM

This section is for developers who are new to ruby development and do not already know how to build and install Ruby gems.

You need to install rubygems from rubyforge.org/projects/rubygems Afterwards you need to install rake and rails

gem install rake

Now change to the RSCM root directory and type

rake gem

This will create a gem for RSCM. To install this gem, you have to change to the pkg directory and type

sudo gem install pkg/rscm-0.3.11.gem

Now you can use RSCM in other Ruby apps with a simple require 'rscm'.