Skab overblik før merge af branches i CVS

Anvendelse af versioneringssystemer af den ene eller anden art er med meget få undtagelser en god idé – hvad enten man arbejder som eneste udvikler på et projekt, er flere der altid arbejder på HEAD af et projekt eller i en af førnævnte konfigurationer har behov for at arbejde i flere branches af et projekt samtidig.

Der opstår imidlertid potentielt komplicerede situationer, når udviklingen på to eller flere branches på et tidspunkt skal flettes sammen og den resulterende kode enten idriftsættes eller benyttes som basis for fortsat udvikling: Der kan være sket ændringer i rigtig mange filer, ved mange forskellige mennesker hænder, i sammenhæng med vidt forskellige projekter og opgaver.

Det kan i den anledning være med til at skabe ro omkring processen, ved inden gennemførelse af fletning, at identificere hvilke filer der er ændret på flere branches – og kombinere denne oplysning med hvilke brugere der har været involveret i de givne ændringer, således at disse på forhånd kan foreberede sig på at håndtere eventuelle konflikter, og efterfølgende at være med til at bekræfte hvorvidt deres respektive ændringer også fungerer efter endt fletning.

Imidlertid er de data CVS kan levere ikke umiddelbart nemme at overskue. Heldigvis kan de med lidt assitance fra Excel relativt nemt beriges og behandles i en pivottabel, så det også for en personkreds med relativt lille kendskab til versionsstyringssystemer forekommer overskueligt, hvor stor en opgave der forestår ved et kommende merge.

cvs history -c -a -p yourRepositoryName >yourRepositoryName.txt

Ovenstående vil trække de informationer ud der er behov for, i form af fommits for alle brugere for et givent repository – og aflevere dem i en tekstfil i et format, der nemt kan importeres i Excel.

Ved import af filen genereret af CVS, vil Text Import Wizard med overvejende sandsynlighed træffe alle de rette valg. Således kan der blot kan vælges “Finish”, når dialogen dukker op ved åbning af filen.

Principielt burde cvs history kunne tage argumenter på formen “-D 2008-01-01”, og derved kun returnere informationer fra dén dato og frem – imidlertid viser praktiske erfaringer, at det kan være særdeles vanskeligt at fremprovokere denne opførsel i praksis. Når dette er tilfældet, er det nødvendigt – og i hvert fald ofte hensigtsmæssigt – at frasortere data der ligger før de branches der er interessante. Dette kan gøres ved at vælge alt, sortere efter kolonne B (Commit Date) og slutteligt at markere og slette de rækker der ligger før dén.

Ved indsættelse af en række i toppen af arket, anbefales følgende navngivning af kolonnerne:

  • Action
  • Commit Date
  • Commit Time
  • Unknown
  • Username
  • Revision
  • Filename
  • Path
  • Equals
  • Client

Med henblik på den videre behandling, indsættes umiddelbart efter kolonnen “Revision” en kolonne der navngives “Branch”. Ved kopiering beregnes værdien for samtlige række i den efter formlen:

Engelsk Excel: =IF(ISNUMBER(SEARCH(".";RIGHT(F2;2);1));LEFT(F2;LEN(F2)-1);LEFT(F2;LEN(F2)-2))

Dansk Excel: =HVIS(ER.TAL(FIND(".";HØJRE(F2;2);1));VENSTRE(F2;LÆNGDE(F2)-1);VENSTRE(F2;LÆNGDE(F2)-2))

Vær opmærksom på, at ovenstående formler ikke tager højde for revisioner højere end 99!

Formlen benytter sig af det faktum, at alt andet en det sidste ciffer i versionsnummeret i CVS angiver en branch, og fungerer ved gennem tekstuel manipulation at fjerne dette.

Hele arket kan derefter markeres, og guiden til indsættelse af en pivottabel kan kaldes.

Her trækkes felterne “Path”, “Filename” og “Branch” til “Row Labels”, feltet “Username” til “Column Labels” og feltet “Action” til “Values”.

Derved vil genereres et ark, der lister hver filnavn under det eller de branches den indgår i, med angivelse af hvilken bruger der har lavet rettelser i hvert branch. Filerne der er interessante i forbindelse med et merge vi være nemme at finde, idet disse vil indgå i flere branches, og dermed have to eller flere linier over filnavnet.

Hermed en efterlysning af andre potentielt interessante efterbehandlingsmetoder og mål, baseret på data trukket ud af CVS.

10 års jubilæum

Hinnerup Net fejrer den 1. august 2008 10 års jubilæum.

Tak for et godt samarbejde til alle vore kunder, samarbejdspartnere og ansatte gennem årene.

Vi ser frem til en fortsat sjov, udfordrende og spændende fremtid med såvel tidligere, nuværende og kommende kunder, samarbejdspartnere samt ansatte.

MS SQL tilgang fra Ruby og Watir

Watir er et framework til automatiserede unit tests af webapplikationer ved brug af et automatiseringslag rettet imod Internet Explorer. Der er tiltag igang for at kunne benytte Watir i Firefox og Safari browserne.

I forbindelse med implementering af adskillige unit tests for en kunde opstod behovet for at kunne checke både datamodel og web-snitfalde imod hinanden. Dataene for de web applikationer der løbende skal kunne testes er placeret i en større SAN baseret MS SQL database.

Ruby har et helt fortrinligt database API, kaldet dbi, som kan anvendes til formålet. Man skal blot installere en ADO wrapper først, da denne ikke som standard medfølger seneste Ruby installationspakke (v186-26). Dette gøres ved først at hente denne dbi pakke indeholdende alle wrappere:
http://rubyforge.org/frs/download.php/655/ruby-dbi-all-0.0.23.tar.gz.

Udpak herfra filen “ruby-dpi-all/lib/dbd_ado/ADO.rb” og kopier denne fil til en nyoprettet “ADO” mappe i din Ruby installationssti, således den endelige placering for wrapper filen bliver “/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb”.

Det er sådanset alt der skal til. Du er nu istand til at tilgå MS SQL databaser fra Ruby, og dermed også fra Watir.

Eksempel:

require 'test/unit'
require 'watir'
require "dbi"

ConnectionString =
  "Provider=SQLOLEDB;" +
  "Data Source=DBSOURCE;" +
  "Initial Catalog=CATALOG;" +
  "User ID=USERNAME;" +
  "Password=PASSWORD;" +
  "Application name=RubyWatir;" +
  "Connection Timeout=0"

class MyTestClass < Test::Unit::TestCase
  ...
  def test_database
    ...
    db = DBI.connect("DBI:ADO:" + ConnectionString)
    sql = "select product, price, description from t_products"
    sth = db.prepare(sql)
    sth.execute
    row = sth.fetch
    puts row
    product = row[0]
    price = row[1]
    description = row[2]
    sth.finish
    db.disconnect
    ...
   end
   ...
end