V2 amok i continuous integration med hjemmelavet kommandolinje-værktøj

Illustration: mast3r/Bigstock
Hvis vi skal holde os relevante for de unge og være seje til open source, skal vi kunne noget med Git, build-værktøjer og automatisering. Men kan gamle rotter overhovedet finde ud af det?

Covid-19 hærger, og vi er alle bekymrede. Derfor bringer Version2 her er et frikvarter for tungsindige hoveder.

I sidste uge stod Version2 i en kattepine. Vi skulle gennemgå 168 blanketter fra en aktindsigt om it-systemet Aula. I PDF-format.

Læs også: Her måtte Bash og Grep give op: Vi skriver et værktøj til at udtrække data fra aktindsigt

Vi ville gerne have et nemt og overskueligt dokument i regnearks-format med de relevante oplysninger fra blanketterne.

For at undgå at skulle copy-paste en hulens masse felter, udtrak vi teksten fra dokumenterne med programmet Pdftotext. Dernæst prøvede vi at skrive et Bash-script, der kunne filtrere de felter fra blanketterne, som vi var interesseret i.

Det gik ikke så godt.

Så i stedet skrev vi et mere generelt kommandolinje-værktøj i Java, med god hjælp fra den gratis webapp Regex101.com, hvor man kan eksperimentere med søgemønstre på interaktiv vis, og generere kode i mange sprog.

I en fart fik vi flikket et lille program sammen, der kan det ønskede - omsætte tekstklumper som:

Skema til indberetning af sikkerhedshændelser
 
Identifikation
Tidspunkt for indberetningen
onsdag maj 15, 2019 13:20:03
 
Referencenummer
a93068d77aca5b0ae2991b8af07021ed6f93da6e
 
Anmelderinformation

– via en simpel søge-syntaks, som journalister og andre ikke-tekniske research-mennesker nok kan finde ud af:

extract2csv "Tidspunkt for indberetningen*Referencenummer" "virksomhedens navn*Afdeling" "Beskriv hændelsen*Hvor fandt hændelsen fysisk sted"  

– til et nemt overskueligt dokument i kommasepareret format:

Illustration: Version2

Programmet er ikke helt færdigt. Det er dårligt testet, har en del fejl og kunne godt bruge nogle flere muligheder - såsom at skrive til en anden uddata-fil, end den, programmet selv bestemmer.

Men ship early, ship often, som man siger. Og vi har da ambitioner, det vil vi slet ikke lægge skjul på: Verdensdominans, intet mindre! Sagde konen i eventyret, knejsede med nakken, og ak! Så lå alle æggene knust der på jorden.

Nu må vi se, hvor langt vi kommer.

Jar, test og automatisering

Til at starte med skal jeg have skrevet unit tests.

Læs også: Sådan skriver du unit tests

Jeg starter med en enkelt, bare et helt simpelt anvendelsesscenarie, så jeg er sikker på, at programmet i den mindste kan det, jeg påstår det kan, under gunstige omstændigheder.

Dernæst er rå Java-klassefiler ikke særlige brugervenlige som binært program. Mange kløjs i den frygtede classpath, og vi tænker jo brugerne som mennesker, der ikke er specielt tekniske.

Så den går slet ikke. I første omgang vil vi skabe en eksekverbar Jar-fil, som er Javas binære pakkeformat. Her slipper man for classpath, og biblioteker er indbygget, så det er en del nemmere at have med at gøre.

Desuden vil vi godt være lidt tjekkede, nu hvor vi har planlagt at blive store kanoner i open source-verdenen.

Hvis vi vil have respekt, tænker jeg, skal vi have ‘continuous integration’ (CI), hvor automatik bygger og tester vores kode, hver gang der er opdateringer. I sidste artikel lagde vi koden på Github, som nu er hjem for vores lille program. Tjenesten byder på CI-faciliteter som er gratis for open souce-projekter som vores.

De tre opgaver - unit test, jar-fil og CI - går hånd i hånd. Første punkt er at vælge et build-værktøj. I Java-verdenen handler det om Ant, Maven og Gradle.

Dengang i det vilde vesten

I gamle dage brugte jeg Ant, som efterhånden har 20 år på bagen. Det var simpelt og fungerede fint til det, jeg skulle: Compile kode, køre test, kopiere til en webserver og tage backup til et netværksdrev - uden Git eller nogen anden slags versionskontrol. De gode, gamle dage i det vilde vesten…

Men der er løbet vand i åen, og man må følge med de unge. Ant har ry for at blive uoverskueligt til større projekter, så de andre valg er dem, der er populære i tiden. Ant kan heller ikke håndtere biblioteker - dependencies - på egen hånd, så her skal jeg under alle omstændigheder gøre noget andet.

Jeg vælger Gradle, som jeg har en smule erfaring med fra værktøjet Android Studio. Jeg kan se, at Githubs indbyggede CI understøtter Gradle, så jeg tænker, at det er den nemmeste fremgangsmåde i min situation. Jeg benytter Eclipse som udviklingsværktøj, og her er Gradle også indbygget. Det må være svaret.

Build.gradle

Omdrejningspunktet i et Gradle-projekt er filen build.gradle, som Eclipse har skrevet for mig. Men det udgangspunkt jeg får, passer skidt til mine behov, og det tager lidt tid og bøvl at finde ud af det.

Her kunne en 'wizard' - en brugervenlig guide - godt have hjulpet mig i gang, Eclipse og Gradle - si’r det bare.

Efter lidt nørkleri, internet-søgning og små-banderi får jeg denne build.gradle-fil i stand:

plugins {
    id 'java'
}
 
repositories {
    jcenter()
}
 
dependencies {
   implementation group: 'org.apache.commons', name: 'commons-csv', version: '1.8'
 
   testImplementation 'junit:junit:4.12'
}

En Gradle-konfigurationsfil er faktisk et program, skrevet i JVM-sproget Groovy, der blærer sig med at være bedst til domænespecifikke sprog, såsom Gradles build-script-sprog.

Læs også: Groovy er stadig godt til DSL'er og integration

Det betyder, at det kan noget mere end rene deklarative sprog som XML, Json og Yaml.

Første blok tuborg-parenteser siger, at vi gerne vil lave et Java-projekt.

Det næste, repositories, fortæller, hvordan vi finder dependency-biblioteker. Det er ren magi og fungerer bare af sig selv. Herligt, i forhold til selv at skulle downloade og konfigurere build-path i Eclipse.

Dernæst kommer dependencies. Her angiver jeg det gængse navn for mit CSV-bibliotek, der skriver de kommaseparerede filer. Det navn kan man finde ved at søge på Mvnrepository.

Den anden dependency er vores unit test-bibliotek, som Eclipse var så venlig selv at skrive - så tak for det.

Og så mener Gradle åbenbart, at mine Java-kildefiler ikke er skrevet i UTF-8. Det synes jeg ærligt talt er lidt fjollet, vi er alle voksne mennesker her. Men det kan fixes med to linjer sidst i build.gradle:

compileJava.options.encoding = "UTF-8"
compileTestJava.options.encoding = "UTF-8"

Vi afvikler test med script

Nu kan jeg afvikle min unit test via Gradle - og det er ikke bare for sjov. Når vi senere skal lave CI på Github, skal det hele jo køre via et script.

I Eclipse kan jeg nu åbne min testklasse i editor-vinduet, højre-klikke på klassenavnet og vælge menuen Run as ≻ Gradle Test. Det tager lidt længere tid, end hvis jeg kørte testen på almindelig vis, men som sagt er det på denne måde, som vores CI-script senere skal afvikle testen på en server i Github-regi.

Som nybegynder vil jeg gerne lige se, at der rent faktisk sker noget. Så jeg skriver til konsollen med System.out i min test. Det kan jeg altid fjerne senere.

Efter test laver Gradle en fyldig rapport i HTML-format hvor konsol-udskrifter kan ses, men det er lidt nemmere, hvis der bare skrives til konsollen i Eclipse. Det kan jeg klare ved at tilføje følgende til build.gradle:

test {
    testLogging {
        showStandardStreams = true
    }
}

Når jeg kører build-kommandoen skriver min test via Gradle: You are here: C:\Users\Tania\workspace\Extract2Csv, så jeg kan se, hvad der er min ‘working directory’, som programmet arbejder med.

Nemmere kommando med Jar

Nu skal vi skabe en jar-fil, som altså er nemmere at afvikle programmet med, end de rå klassefiler. Det kan se sådan ud, når kommandoen køres:

java -jar Extract2Csv.jar "Tidspunkt for indberetningen*Referencenummer" "virksomhedens navn*Afdeling" "Beskriv hændelsen*Hvor fandt hændelsen fysisk sted"

Det er en lille forbedring, end med klassefilerne og classpath.

Sådan én er nem at skabe med Gradle. Jeg søger lidt på nettet, og det fører til denne klamamse i build.gradle:

jar {
  manifest {
    attributes(
      'Main-Class': 'extract2csv.Extract2Csv'
    )
  }
  from {
    configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
  }
}

Gradle-blokken siger: Lav en Jar-fil, og skriv en Main-Class i manifest-filen. Det er det, der gør Jar-filen eksekverbar med kommandoen, vi så ovenfor. Næste del siger: Tag de biblioteker, der er på classpath’en med i Jar-filen.

I Eclipse kan jeg nu vælge view’et Gradle Tasks og klikke på punktet build - så compiler og tester Gradle mit projekt, og skaber Jar-filen.

Det kunne min gamle ven Ant nok også gøre, men nu synes jeg, at jeg taler de unges sprog, my fellow homies.

Det var så langt, vi nåede i denne omgang. Ret beset kom vi aldrig i gang med Githubs CI-funktionalitet, men nu har vi kridtet banen op og går til makronerne i næste artikel.

Stay tuned & stay safe.

Tips og korrekturforslag til denne historie sendes til tip@version2.dk
Følg forløbet
Kommentarer (3)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Claus Larsen

Egen udvikling er fedt, men der er lavet i tusindvis af lignende værktøjer.
Årsagen er vel, at det er for svært, at sætte sig ind i de eksisterende værktøjer.
Spørgsmålet er så, om det ikke alligevel havde taget kortere tid, at sætte sig ind i et eksisterende værktøj.
Det handler vel primært om, at sætte sig ind i regex.
Problemet her kan løses i mange værktøjer, med 'sed' kan det gøres noget lignende:
cat pdf.txt | tr '\n' '\r' | sed 's/.Tidspunkt for indberetningen[[:space:]]([^\r]).Referencenummer[[:space:]]([^\r])./\1,\2/' | tr '\r' '\n'
Som giver output:
onsdag maj 15, 2019 13:20:03,a93068d77aca5b0ae2991b8af07021ed6f93da6e

  • 0
  • 0
Log ind eller Opret konto for at kommentere