Arbeidsflyt for publisering av artikler

Eirik Rolland Enger February 21, 2026
Source

En hyllest til mise-en-place

{{}}

Installer et nytt prosjekt fra paper-publishing-process med

  • Automatisk kompilering av main.pdf, review-.pdf og diff-.pdf
  • Git Tag-basert versjonering og generering av endringslogg
  • CI/CD-pipeline med kompilering og nye releaser

{{< video src="compile-all.mp4" loop="true" autoplay="true" muted="true" >}}

{{}}

En frustrasjon fra da jeg først begynte å skrive artikler som skulle sendes inn til tidsskrifter og gå gjennom en vurderingssyklus var å kunne holde styr på hvilken versjon som ble sendt inn til hvilket tidspunkt. Hvilken versjon skal jeg svare på, hvilken versjon skal den oppdaterte versjonen differensieres mot? Dette var en svært manuell prosess hvor jobben med å holde styr på hva som skulle sendes inn i nyeste revisjon tidvis føltes like stor som selve skrivingen.

Heldigvis finnes det løsninger.

Oppsett av verktøy og repo

Alt skal kunne leve uavhengig av systemet man først utvikler på, så vi lager oss et Git-repo som alle filene kan leve i. I denne guiden kommer vi til å benytte GitHub sin workflow i utstrakt grad, så vi oppretter repoet der. Jeg kalte min paper-publishing-process, så la oss klone det ned:

Videre trenger vi å kunne installere alt av programvare, og til det bruker vi mise. Først må vi installere mise; besøk nettsiden, eller kjør følgende kommando:

Deretter oppretter vi fila mise.toml i prosjektet sin root:

Denne må vi gi tillatelse til mise til å bruke, mise trust, før vi installerer alt med mise install.

I den første commiten la jeg til en enkel lisensfil (MIT) og en .gitignore egnet for TeX-utvikling.

→ Se commit ce3150c.

La oss i samme slengen legge til noen filer som er behjelpelig med å holde repoet opp til en god standard hva angår formatering:

  • tex-fmt.toml: Formatering av .tex og .bib
  • .taplo.toml: Formatering av .toml
  • .yamlfmt.yml: Formatering av .yml
  • hk.pkl: Formatering og linting

Denne endringen oppdaterer også mise.toml og lager fila tex/main.tex.

→ Se commit b161e41.

Vi kan sjekke at alt så langt er som det skal:

Automatisk kompilering av TeX

Lokal kompilering med mise

Vi er nå klare til å jobbe med TeX-filene! Vi ønsker å kunne skrive i tex/main.tex, og hver gang vi lagrer så skal PDF-en oppdateres automatisk. Vi ser igjen til mise for å få denne funksjonaliteten.

→ Se commit e7127b4.

{{< details "Motivasjon for mise tasks" >}}

Vi legger i commiten over til en mise task kalt "localize-bib-paths". Motivasjonen bak det er at "compile" task (introdusert litt senere) vil kjøre den slik at når man utvikler lokalt vil alle referanser komme fra den globale hovedreferansen. Dette er nyttig i tilfeller hvor man ønsker å legge til en ny referanse i TeX-dokumentet som allerede finnes i hovedreferansen. Om man bruker en moderne editor vil den gi completion-forslag, noe som ikke vil være tilgjengelig i de genererte referansefilene for nye referanser.

{{< /details >}}

Vi kan nå kjøre

Den feiler! Dette er grunnet det først, litt spesielle valget vi gjør i denne arbeidsflyten.

Bibfish

For å kunne ha så minimale .bib-filer som mulig i repoet, blir alle generert fra en lokal "hovedreferansefil". Denne fila er det LOCAL_BIB_PATH verdien som vi la til i mise.toml peker på. Denne hovedreferansen er tiltenkt å være en fil som lever kun lokalt, og ikke i Git-repoet, og skal kunne levere referanser ikke bare til dette prosjektet, men til alle dine TeX-prosjekter! Bibfish vil da lese den og generere en referansefil basert kun på de referansene som finnes i en gitt TeX-fil.

Bibfish støtter de fleste vanlige siteringsformat (for eksempel \cite, \citet, osv.), men kan enkelt utvides med egne format. I mise.toml har vi lagt til citeA, og spesifiserer også cite, citet og citep (bibfish -c 'cite,citet,citep,citeA' -f main.tex {{ env.LOCAL_BIB_PATH }}.bib main.bib).

La oss fikse feilen fra i stad ved å

  1. Legge mise.local.toml til i .gitignore
  2. Spesifisere en lokal Bib-fil i mise.local.toml

{{}}

Merk at den lokale fila sin posisjon enten må være "absolutt" (/home/user/the-file), eller "relativ" fra tex-mappen, samt at den spesifiseres uten .bib.

{{< /callout >}}

Jeg la også til den lokale hovedreferansen her for å illustrere med et minimalt eksempel, men vanligvis ville jeg lagt den utenfor repoet. Legg også til

→ Se commit a149cdf.

Når vi nå forsøker å kompilere, ingen error!

BBL-filer og referanser i Git

La oss legge til noen referanser.

Vi lager oss også en generell compile-task i mise:

Når vi nå kjører mise watch compile vil en ny fil bli generert: tex/main.bbl. Denne er det vanlig å ignorere, men vi tenger denne i fremtiden, så vi fjerner den fra .gitignore.

Den inneholder en ny .bbl-fil, og .bib-fila har blitt oppdatert med én (og bare én) referanse, nemlig den vi la til i tex/main.tex!

→ Se commit 1a523ea.

Håndtering av TeX-pakker med tlmgr

Vi bruker tinytex som TeX-distribusjon i dette prosjektet. Den er som navnet antyder mye mindre enn den vanligere TeX-live/TeX-live-full. Det betyr også at vi litt oftere vil oppleve at pakker ikke er tilgjengelige, men det gir oss til gjengjeld mer kontroll. La oss bruke et knippe pakker som ikke er å finne i TinyTeX.

→ Se commit fe28c24 for oppdatert tex/main.tex og mise.toml.

Om du først endrer tex/main.tex med innholdet i commiten over og har mise watch compile kjørende burde den feile, og klage på at underscore ikke er tilgjengelig. Legg så til postinstall-hook i mise.toml, og kjør mise install.

Dette vil sørge for at diverse pakker installeres via tlmgr. Fordelen med dette oppsettet er at mange tidsskrifter er veldig kresne på hvilke pakker de aksepterer. Om man da har skrevet et langt manuskript som benytter mange pakker og som kompilerer fint lokalt fordi man har brukt TeX-live-full, kan det fort bli vanskelig å finne ut av hva som må bort om kompilering på tidsskriftet sin server krasjer.

Arbeidsflyt for lokal utvikling

Vi er nå i mål med arbeidsflyten for lokale TeX-filer! Kjør mise watch compile, skriv ned alle dine gode ideer, og hver gang tex/main.tex lagres vil kompileringen kjøre. Legg merke til hvordan tex/main.bib oppdateres i terminalvinduet øverst til høyre når jeg legger til og fjerner referanser.

{{< video src="compile.mp4" loop="true" autoplay="true" muted="true" >}}

Neste steg: automatisk kompilering på GitHub, støtte for versjonering via Git og rutiner for svar til tilbakemelding fra tidsskrifter.

CI/CD-pipeline på GitHub

Git commit hooks

Siden vi har verktøy for å formatere koden samt et fungerende hk oppsett, kan vi enkelt sette opp Git commit hooks:

{{}}

Siden mise run|watch compile gjør alle \bibliography{...} om til å bruke den lokale hovedreferansen, mens pre-commit hooken via hk gjør de om til å bruke de genererte bib-filene vil det oppstå konflikt mellom de.

Hver gang man lager en commit er det derfor lurt å stoppe mise watch compile, slik at den ikke skriver over før man er ferdig med commiten.

{{< /callout >}}

Automatisk bygging og release

For å sette opp CI/CD lager vi fila mise.ci.toml, samt tre filer i .github/workflows og .mise/tasks:

  • .github/workflows/build.yml

    Kompilerer alle PDF-er for hver push til main-grenen på GitHub.

  • .github/workflows/fix-bib-filepath.yml

    En ekstra sjekk som sørger for at rett bib-fil benyttes til å kompilere PDF-ene.

  • .mise/tasks/package

    Legger alle filer som et tidsskrift ønsker i et arkiv, for enkel opplasting ved innsendelse.

→ Se commit 93c8487 for innholdet i filene.

Den commiten feilet faktisk i CI på GitHub. Her hadde jeg altså glemt at alle filer i .mise/tasks må være kjørbare (executable bit), det vil si jeg måtte

Jeg endret også på hvordan TinyTeX blir installert, og la til oppdatering av tlmgr i postinstall hook.

→ Se commit 06262fd.

Under ser vi at CI/CD kjørte uten error og ga oss en paper-assets artefakt.

{{

}}

Versjonering og svar til tidsskrift

Vi er nå nesten klare til å sende manuskriptet inn til et tidsskrift, men aller først skal vi sette opp versjonering i Git som genererer nye utgivelser med endringslogg. Git-Cliff er et veldig fleksibelt og kraftfullt verktøy til nettopp dette, og vi konfigurerer den med cliff.toml. Denne fila er helt generell, med unntak av de siste to linjene, som vist under. De indikerer eier av repoet og navnet på repoet.

Vi kan nå sette en Git Tag på siste commit for å lage vår første versjon av manuskriptet!

→ Se commit bfe67c6.

Og der har vi den, vår første release! Den fikk navn ut fra det vi tagget i Git Tag (v1.0.0), en tag som er helt vilkårlig, men som i dette tilfellet følger SemVer-standarden. Vi kunne like gjerne benyttet CalVer (f.eks. vYYYY.MM.P) v2026.03.0, eller noe helt egendefinert som rel1. Vi kan tilogmed bytte standard; neste versjon kan helt fint følge CalVer selv om vi i første release brukte SemVer. Så lenge du holder deg til en fast standard, bruk hva enn som føles mest naturlig.

{{

}}

Som et vedlegg (artefakt) til releasen har vi både paper.zip og main.pdf. Arkivet paper.zip inneholder alle filer spesifisert i .mise/tasks/package, og mer spesifikt i Bash-arrayet files. Her er det nyttig å legge til alle filer som trengs for å generere PDF-en, slik at, ved opplasting til tidsskriftet, kan man enkelt plukke ut alle filene fra arkivet og laste opp, i stedet for å lete gjennom repoet etter alle filer man trenger.

{{< details "Om Git Tag innhold" >}}

I git tag-kommandoen anga vi -a flagget (annotation), og to -m flagg. De står for message, men blir ikke del i release teksten som vi ser i bildet over, siden det genereres av Git-Cliff. Den vil dog være synlig i Git Tags, se Tags.

{{< /details >}}

Review-syklus og revisjon

Motta og sette opp revisjon

Selv om vi var aldri så fornøyd med manuskriptet får vi sannsynligvis tilbake en review og forespørsel om å forbedre enkelte passasjer. Det er nå den gode jobben vi har lagt ned i Git og versjonering virkelig kommer til syne.

Vi lager oss en siste mise task: .mise/tasks/setup-revision. → Se commit b490542 (legger også til diff.tex-filer i .github/workflows/build.yml).

La oss teste den:

Hele seks nye filer ble generert! Dette inkluderer to TeX-filer som skal fungere som svar til reviewerne og differanse mellom forrige Git Tag og det nye manuskriptet, samt fire Mise task-filer som skal kompilere de to TeX-filene. Disse avhenger av noe TeX-kode som vi også legger til:

  • tex/reviewresponse.cls: klassen som review-dokumentene bruker
  • tex/reviewresponse-extra.sty: ekstra TeX-kode som setter opp formatering i review-dokumentene

{{}}

Om du på et tidspunkt tenker at du er klar til å sende inn manuskriptet og lager en Git Tag mot siste commit, men så senere innser at du trenger å gjøre ytterligere endringer kan man enkelt flytte eller slette Git Tags. Hvis man ikke flytter en feilplassert Git Tag vil ikke setup-revision tasken fungere som forventet, siden den da sammenligner nåværende main.tex med en Git Tag som peker mot filer som aldri ble sendt inn til tidsskriftet.

Git Tags kan slettes med git tag --delete , og festes på en spesifikk commit med git tag -a -m "Message".

{{}}

La oss nå kjøre mise watch compile!

{{< video src="compile-all.mp4" loop="true" autoplay="true" muted="true" >}}

Ok, hva foregår egentlig i videoen? Videoen starter rett etter at jeg har kjørt mise run setup-revision som genererer de seks filene for "diff" og "review". Først i videoen kjøres så mise watch compile, som så går i bakgrunnen gjennom hele videoen. Denne ene kommandoen kompilerer main.pdf, review-v1.0.0.pdf og diff-v1.0.0.pdf, samt at den følger med på endringer. Deretter åpner vi diff-v1.0.0.pdf og review-v1.0.0.pdf, før vi gjør en endring i main.tex. Endringen blir umiddelbart synlig i main.pdf og diff-v1.0.0.pdf. Til slutt gjør vi en endring i review-v1.0.0.tex, som like umiddelbart blir synlig i review-v1.0.0.pdf.

Differansen mellom den nye main.tex/main.pdf og den vi sendte inn i versjon v1.0.0 kan vi enkelt generere uten at filen eksisterer lokalt. Siden vi har en Git Tag refererer vi bare til den, og sammenligner med fila på det tidspunktet i Git-historien. Det er i dette steget vi er avhengige av .bbl-filene, som inneholder den kompilerte (eksakte) bibliografien som ble brukt til å generere PDF-ene. Dette gjøres i de genererte create-taskene med kommandoen

→ Se commit 68d913f for de nye filene.

Sende inn revidert manuskript

La oss si at vi nå er fornøyd med våre siste endringer og er klare til å sende inn på nytt til tidsskriftet. Da setter vi igjen en Git Tag på siste commit, dytter den opp og venter på at siste versjon skal gjøres klar for oss i et pent format.

Siden jeg personlig liker CalVer i denne sammenhengen bytter jeg til det nå:

{{

}}

Om vi nå får nye runder med endringer fra reviewerne, gjør vi bare det samme på nytt:

  1. mise run setup-revision
  2. mise watch compile: Gjør alle endringer på main.tex og review-.tex som vi mener er nødvendig
  3. git commit ...
  4. git tag -a '...' -m '...'
  5. git push --tags

{{<details "En gang til">}}

Her er for eksempel output fra mise run setup-revision nå etter at jeg har laget v2026.03.0:

Og videre mise run compile. Legg merke til review-v1.0.0: skipping, newer revision exists, og tilsvarende for "diff". Ingenting kompileres om ikke det virkelig er nødvendig!

Og slik ser siste release ut etter at de siste nødvendige endringene ble gjort, klar til å publiseres!

{{}}

Klargjøring og README

Repoet fungerer nå fullt og helt til å både enkelt klargjøre et manuskript for innsendelse, og til å lage svar og differanse/endringsdokument på eventuelle reviewer.

Men for å gjøre selve repoet litt mer innbydende er det god praksis å også lage en README-fil. Med alle releasene vi har laget og artefaktene til de er det enkelt å linke til filer på ulike stadier av prosessen.

→ Se commit b3cbc9d for endringene gjort i README.md.

Videre utvidelser

Endringslogg

Vi har allerede satt opp en hel del automasjon, men vi kan selvfølgelig fortsette enda lenger. Git-Cliff kan settes opp til å skrive til en fil, typisk kalt CHANGELOG.md, som i tillegg til at man har endringer mellom versjoner i hver release, så står hele endringsloggen i den fila.

PR-basert versjonering

Man kan også sette opp PR-basert (pull request) versjonering som benytter Conventional commits til å automatisk generere nye forslag til releaser. Dette krever en litt større endring i konfigurasjonen i GitHub CI/CD.

Sikker versjonering av GitHub Actions

Som du kanskje har lagt merke til så er alle actions brukt i GitHub workflow spesifisert med en lang hash, etterfulgt av en kommentar som beskriver hvilken versjon den peker på. Dette er god praksis fordi, som så vidt nevnt tidligere, Git Tags er "mutable"; de kan forandres og flyttes på. Dette gjør de til en potensiell angrepsflate, og det er derfor tryggere å spesifisere commit hash, siden den er "immutable", uforanderlig.

For å enkelt holde seg oppdatert med de siste versjonene kan man bruke pinact-action, men denne vil trenge en TOKEN med rettigheter til å skrive til .github/workflows-filene.

Enda mer mise-magi

Vi har allerede etablert at mise-en-place er en strålende programvare, og den kan gjøre enda litt mer. Tre kommandoer som er nyttige for å ha et repo som både er lett å sette opp, og har en veldokumentert flyt kan man kjøre

Den første kommandoen skriver en fil med låste versjoner som er tilpasset installasjon til alle vanlige plattformer. Andre kommando genererer et shell-skript som installerer samme versjon av mise-en-place som er i bruk, mens den siste kommandoen genererer dokumentasjon for alle tasks som er definert med mise-en-place.

→ Se commit 9c1fb30 for filer som legger til funksjonalitet for versjonering av actions og mise bootstraping.

Discussion in the ATmosphere

Loading comments...