{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreieura4bk23l6xt52gidymgokjvidbg3unbsfi2mivtwldgftgbk7q",
"uri": "at://did:plc:jhmdbcph6xja3hamtoi4kdy4/app.bsky.feed.post/3moyc7o2h2m2i"
},
"canonicalUrl": "https://eirik.re/blog/paper-publishing-workflow/index.nb",
"description": "En hyllest til mise-en-place",
"path": "/blog/paper-publishing-workflow/index.nb",
"publishedAt": "2026-02-21T21:16:35.000Z",
"site": "at://did:plc:jhmdbcph6xja3hamtoi4kdy4/site.standard.publication/3moyb2g35kh2t",
"tags": [
"mise",
"latex",
"tinytex",
"paper"
],
"textContent": "> _En hyllest til mise-en-place_\n\n{{<callout context=\"tip\" title=\"TL;DR\" icon=\"rocket\">}}\n\nInstaller et nytt prosjekt fra\npaper-publishing-process med\n\n- Automatisk kompilering av main.pdf, review-<git-tag>.pdf og diff-<git-tag>.pdf\n- Git Tag-basert versjonering og generering av endringslogg\n- CI/CD-pipeline med kompilering og nye releaser\n\n{{< video src=\"compile-all.mp4\" loop=\"true\" autoplay=\"true\" muted=\"true\" >}}\n\n{{</callout>}}\n\nEn frustrasjon fra da jeg først begynte å skrive artikler som skulle sendes inn til\ntidsskrifter og gå gjennom en vurderingssyklus var å kunne holde styr på hvilken versjon\nsom ble sendt inn til hvilket tidspunkt. Hvilken versjon skal jeg svare på, hvilken\nversjon skal den oppdaterte versjonen differensieres mot? Dette var en svært manuell\nprosess hvor jobben med å holde styr på hva som skulle sendes inn i nyeste revisjon\ntidvis føltes like stor som selve skrivingen.\n\nHeldigvis finnes det løsninger.\n\nOppsett av verktøy og repo\n\nAlt skal kunne leve uavhengig av systemet man først utvikler på, så vi lager oss et\nGit-repo som alle filene kan leve i. I denne guiden kommer vi til å benytte GitHub sin\nworkflow i utstrakt grad, så vi oppretter repoet der. Jeg\nkalte min paper-publishing-process, så la oss klone det ned:\n\nVidere trenger vi å kunne installere alt av programvare, og til det bruker vi\nmise. Først må vi installere mise;\nbesøk nettsiden, eller kjør følgende kommando:\n\nDeretter oppretter vi fila mise.toml i prosjektet sin root:\n\nDenne må vi gi tillatelse til mise til å bruke, mise trust,\nfør vi installerer alt med mise install.\n\nI den første commiten la jeg til en enkel lisensfil (MIT) og en .gitignore egnet for\nTeX-utvikling.\n\n_→ Se commit\nce3150c._\n\nLa oss i samme slengen legge til noen filer som er behjelpelig med å holde repoet opp\ntil en god standard hva angår formatering:\n\n- tex-fmt.toml: Formatering av .tex og .bib\n- .taplo.toml: Formatering av .toml\n- .yamlfmt.yml: Formatering av .yml\n- hk.pkl: Formatering og linting\n\nDenne endringen oppdaterer også mise.toml og lager fila tex/main.tex.\n\n_→ Se commit\nb161e41._\n\nVi kan sjekke at alt så langt er som det skal:\n\nAutomatisk kompilering av TeX\n\nLokal kompilering med mise\n\nVi er nå klare til å jobbe med TeX-filene! Vi ønsker å kunne skrive i tex/main.tex, og\nhver gang vi lagrer så skal PDF-en oppdateres automatisk. Vi ser igjen til\nmise for å få denne funksjonaliteten.\n\n_→ Se commit\ne7127b4._\n\n{{< details \"Motivasjon for mise tasks\" >}}\n\nVi legger i commiten over til en mise task kalt\n\"localize-bib-paths\". Motivasjonen bak det er at \"compile\" task (introdusert litt\nsenere) vil kjøre den slik at når man utvikler lokalt vil alle referanser komme fra den\nglobale hovedreferansen. Dette er nyttig i tilfeller hvor man ønsker å legge til en ny\nreferanse i TeX-dokumentet som allerede finnes i hovedreferansen. Om man bruker en\nmoderne editor vil den gi completion-forslag, noe som ikke vil være tilgjengelig i de\ngenererte referansefilene for _nye_ referanser.\n\n{{< /details >}}\n\nVi kan nå kjøre\n\nDen feiler! Dette er grunnet det først, litt spesielle valget vi gjør i denne\narbeidsflyten.\n\nBibfish\n\nFor å kunne ha så minimale .bib-filer som mulig i repoet, blir alle generert fra en\nlokal \"hovedreferansefil\". Denne fila er det LOCAL_BIB_PATH verdien som vi la til i\nmise.toml peker på. Denne hovedreferansen er tiltenkt å være en fil som lever kun\nlokalt, og ikke i Git-repoet, og skal kunne levere referanser ikke bare til dette\nprosjektet, men til alle dine TeX-prosjekter! Bibfish vil da lese den og generere en\nreferansefil basert kun på de referansene som finnes i en gitt TeX-fil.\n\nBibfish støtter de fleste vanlige siteringsformat (for eksempel \\cite, \\citet,\nosv.), men kan enkelt utvides med egne format. I mise.toml har vi lagt til citeA, og\nspesifiserer også cite, citet og citep\n(bibfish -c 'cite,citet,citep,citeA' -f main.tex {{ env.LOCAL_BIB_PATH }}.bib main.bib).\n\nLa oss fikse feilen fra i stad ved å\n\n1. Legge mise.local.toml til i .gitignore\n2. Spesifisere en lokal Bib-fil i mise.local.toml\n\n{{<callout context=\"caution\" title=\"Lokal bib-fil\" icon=\"alert-triangle\">}}\n\nMerk at den lokale fila sin posisjon enten må være \"absolutt\" (/home/user/the-file),\neller \"relativ\" fra tex-mappen, samt at den spesifiseres uten .bib.\n\n{{< /callout >}}\n\nJeg la også til den lokale hovedreferansen her for å illustrere med et minimalt\neksempel, men vanligvis ville jeg lagt den utenfor repoet. Legg også til\n\n_→ Se commit\na149cdf._\n\nNår vi nå forsøker å kompilere, ingen error!\n\nBBL-filer og referanser i Git\n\nLa oss legge til noen referanser.\n\nVi lager oss også en generell compile-task i mise:\n\nNår vi nå kjører mise watch compile vil en ny fil bli generert: tex/main.bbl. Denne\ner det vanlig å ignorere, men vi tenger denne i fremtiden, så vi fjerner den fra\n.gitignore.\n\nDen inneholder en ny .bbl-fil, og .bib-fila har blitt oppdatert med én (og bare én)\nreferanse, nemlig den vi la til i tex/main.tex!\n\n_→ Se commit\n1a523ea._\n\nHåndtering av TeX-pakker med tlmgr\n\nVi bruker tinytex som TeX-distribusjon i dette prosjektet.\nDen er som navnet antyder mye mindre enn den vanligere TeX-live/TeX-live-full. Det betyr\nogså at vi litt oftere vil oppleve at pakker ikke er tilgjengelige, men det gir oss til\ngjengjeld mer kontroll. La oss bruke et knippe pakker som ikke er å finne i TinyTeX.\n\n_→ Se commit\nfe28c24 for\noppdatert tex/main.tex og mise.toml._\n\nOm du først endrer tex/main.tex med innholdet i commiten over og har\nmise watch compile kjørende burde den feile, og klage på at underscore ikke er\ntilgjengelig. Legg så til postinstall-hook i mise.toml, og kjør mise install.\n\nDette vil sørge for at diverse pakker installeres via tlmgr. Fordelen med dette\noppsettet er at mange tidsskrifter er veldig kresne på hvilke pakker de aksepterer. Om\nman da har skrevet et langt manuskript som benytter mange pakker og som kompilerer fint\nlokalt fordi man har brukt TeX-live-full, kan det fort bli vanskelig å finne ut av hva\nsom må bort om kompilering på tidsskriftet sin server krasjer.\n\nArbeidsflyt for lokal utvikling\n\nVi er nå i mål med arbeidsflyten for lokale TeX-filer! Kjør mise watch compile, skriv\nned alle dine gode ideer, og hver gang tex/main.tex lagres vil kompileringen kjøre.\nLegg merke til hvordan tex/main.bib oppdateres i terminalvinduet øverst til høyre når\njeg legger til og fjerner referanser.\n\n{{< video src=\"compile.mp4\" loop=\"true\" autoplay=\"true\" muted=\"true\" >}}\n\nNeste steg: automatisk kompilering på GitHub, støtte for versjonering via Git og rutiner\nfor svar til tilbakemelding fra tidsskrifter.\n\nCI/CD-pipeline på GitHub\n\nGit commit hooks\n\nSiden vi har verktøy for å formatere koden samt et fungerende hk\noppsett, kan vi enkelt sette opp Git commit hooks:\n\n{{<callout context=\"danger\" title=\"Pre-commit vs. mise run compile\" icon=\"alert-octagon\">}}\n\nSiden mise run|watch compile gjør alle \\bibliography{...} om til å bruke den lokale\nhovedreferansen, mens pre-commit hooken via hk gjør de om til å bruke de genererte\nbib-filene vil det oppstå konflikt mellom de.\n\nHver gang man lager en commit er det derfor lurt å stoppe mise watch compile, slik at\nden ikke skriver over før man er ferdig med commiten.\n\n{{< /callout >}}\n\nAutomatisk bygging og release\n\nFor å sette opp CI/CD lager vi fila mise.ci.toml, samt tre filer i .github/workflows\nog .mise/tasks:\n\n- .github/workflows/build.yml\n\n Kompilerer alle PDF-er for hver push til main-grenen på GitHub.\n\n- .github/workflows/fix-bib-filepath.yml\n\n En ekstra sjekk som sørger for at rett bib-fil benyttes til å kompilere PDF-ene.\n\n- .mise/tasks/package\n\n Legger alle filer som et tidsskrift ønsker i et arkiv, for enkel opplasting ved\n innsendelse.\n\n_→ Se commit\n93c8487 for\ninnholdet i filene._\n\nDen commiten feilet faktisk i CI på GitHub. Her hadde jeg altså glemt at alle filer i\n.mise/tasks må være kjørbare (executable bit), det vil si jeg måtte\n\nJeg endret også på hvordan TinyTeX blir installert, og la til oppdatering av tlmgr i\npostinstall hook.\n\n_→ Se commit\n06262fd._\n\nUnder ser vi at CI/CD kjørte uten error og ga oss en paper-assets artefakt.\n\n{{<figure src=\"first-ci.png\" alt=\"Første CI/CD-kjøring\" caption=\"Første CI/CD-kjøring\" >}}\n\nVersjonering og svar til tidsskrift\n\nVi er nå nesten klare til å sende manuskriptet inn til et tidsskrift, men aller først\nskal vi sette opp versjonering i Git som genererer nye utgivelser med endringslogg.\nGit-Cliff er et veldig fleksibelt og kraftfullt verktøy til\nnettopp dette, og vi konfigurerer den med cliff.toml. Denne fila er helt generell, med\nunntak av de siste to linjene, som vist under. De indikerer eier av repoet og navnet på\nrepoet.\n\nVi kan nå sette en Git Tag på siste commit for å lage vår første versjon av\nmanuskriptet!\n\n_→ Se commit\nbfe67c6._\n\nOg der har vi den, vår\nførste release!\nDen fikk navn ut fra det vi tagget i Git Tag (v1.0.0), en tag som er helt vilkårlig,\nmen som i dette tilfellet følger SemVer-standarden. Vi kunne like gjerne benyttet CalVer\n(f.eks. vYYYY.MM.P) v2026.03.0, eller noe helt egendefinert som rel1. Vi kan\ntilogmed bytte standard; neste versjon kan helt fint følge CalVer selv om vi i første\nrelease brukte SemVer. Så lenge du holder deg til en fast standard, bruk hva enn som\nføles mest naturlig.\n\n{{<figure src=\"first-release.png\" alt=\"Første release\" caption=\"Første release\" >}}\n\nSom et vedlegg (artefakt) til releasen har vi både paper.zip og main.pdf. Arkivet\npaper.zip inneholder alle filer spesifisert i .mise/tasks/package, og mer spesifikt\ni Bash-arrayet files. Her er det nyttig å legge til alle filer som trengs for å\n_generere_ PDF-en, slik at, ved opplasting til tidsskriftet, kan man enkelt plukke ut\nalle filene fra arkivet og laste opp, i stedet for å lete gjennom repoet etter alle\nfiler man trenger.\n\n{{< details \"Om Git Tag innhold\" >}}\n\nI git tag-kommandoen anga vi -a flagget (annotation), og to -m flagg. De står for\nmessage, men blir ikke del i release teksten som vi ser i bildet over, siden det\ngenereres av Git-Cliff. Den vil dog være synlig i Git Tags, se\nTags.\n\n{{< /details >}}\n\nReview-syklus og revisjon\n\nMotta og sette opp revisjon\n\nSelv om vi var aldri så fornøyd med manuskriptet får vi sannsynligvis tilbake en review\nog forespørsel om å forbedre enkelte passasjer. Det er nå den gode jobben vi har lagt\nned i Git og versjonering virkelig kommer til syne.\n\nVi lager oss en siste mise task: .mise/tasks/setup-revision.\n_→ Se commit\nb490542 (legger\nogså til diff.tex-filer i .github/workflows/build.yml)._\n\nLa oss teste den:\n\nHele seks nye filer ble generert! Dette inkluderer to TeX-filer som skal fungere som\nsvar til reviewerne og differanse mellom forrige Git Tag og det nye manuskriptet, samt\nfire Mise task-filer som skal kompilere de to TeX-filene. Disse avhenger av noe TeX-kode\nsom vi også legger til:\n\n- tex/reviewresponse.cls: klassen som review-dokumentene bruker\n- tex/reviewresponse-extra.sty: ekstra TeX-kode som setter opp formatering i\n review-dokumentene\n\n{{<callout context=\"note\" title=\"Feil Git Tag\" icon=\"bulb\">}}\n\nOm du på et tidspunkt tenker at du er klar til å sende inn manuskriptet og lager en Git\nTag mot siste commit, men så senere innser at du trenger å gjøre ytterligere endringer\nkan man enkelt flytte eller slette Git Tags. Hvis man ikke flytter en feilplassert Git\nTag vil ikke setup-revision tasken fungere som forventet, siden den da sammenligner\nnåværende main.tex med en Git Tag som peker mot filer som aldri ble sendt inn til\ntidsskriftet.\n\nGit Tags kan slettes med git tag --delete <git-tag>, og festes på en spesifikk commit\nmed git tag -a <git-tag> <commit-hash> -m \"Message\".\n\n{{</callout>}}\n\nLa oss nå kjøre mise watch compile!\n\n{{< video src=\"compile-all.mp4\" loop=\"true\" autoplay=\"true\" muted=\"true\" >}}\n\nOk, hva foregår egentlig i videoen? Videoen starter rett etter at jeg har kjørt\nmise run setup-revision som genererer de seks filene for \"diff\" og \"review\". Først i\nvideoen kjøres så mise watch compile, som så går i bakgrunnen gjennom hele videoen.\nDenne ene kommandoen kompilerer main.pdf, review-v1.0.0.pdf og diff-v1.0.0.pdf,\nsamt at den følger med på endringer. Deretter åpner vi diff-v1.0.0.pdf og\nreview-v1.0.0.pdf, før vi gjør en endring i main.tex. Endringen blir umiddelbart\nsynlig i main.pdf og diff-v1.0.0.pdf. Til slutt gjør vi en endring i\nreview-v1.0.0.tex, som like umiddelbart blir synlig i review-v1.0.0.pdf.\n\nDifferansen mellom den nye main.tex/main.pdf og den vi sendte inn i versjon v1.0.0\nkan vi enkelt generere uten at filen eksisterer lokalt. Siden vi har en Git Tag\nrefererer vi bare til den, og sammenligner med fila på det tidspunktet i Git-historien.\nDet er i dette steget vi er avhengige av .bbl-filene, som inneholder den kompilerte\n(eksakte) bibliografien som ble brukt til å generere PDF-ene. Dette gjøres i de\ngenererte create-taskene med kommandoen\n\n_→ Se commit\n68d913f for de nye\nfilene._\n\nSende inn revidert manuskript\n\nLa oss si at vi nå er fornøyd med våre siste endringer og er klare til å sende inn på\nnytt til tidsskriftet. Da setter vi igjen en Git Tag på siste commit, dytter den opp og\nventer på at siste versjon skal gjøres klar for oss i et pent format.\n\nSiden jeg personlig liker CalVer i denne sammenhengen bytter jeg til det nå:\n\n{{<figure src=\"second-release.png\" alt=\"Andre release, med arkiv (paper.zip) og de tre PDF-ene\" caption=\"Andre release, med arkiv (paper.zip) og de tre PDF-ene\" >}}\n\nOm vi nå får nye runder med endringer fra reviewerne, gjør vi bare det samme på nytt:\n\n1. mise run setup-revision\n2. mise watch compile: Gjør alle endringer på main.tex og review-<git-tag>.tex som\n vi mener er nødvendig\n3. git commit ...\n4. git tag -a '...' -m '...'\n5. git push --tags\n\n{{<details \"En gang til\">}}\n\nHer er for eksempel output fra mise run setup-revision nå etter at jeg har laget\nv2026.03.0:\n\nOg videre mise run compile. Legg merke til\nreview-v1.0.0: skipping, newer revision exists, og tilsvarende for \"diff\". Ingenting\nkompileres om ikke det virkelig er nødvendig!\n\nOg slik ser\nsiste release\nut etter at de siste nødvendige endringene ble gjort, klar til å publiseres!\n\n{{</details>}}\n\nKlargjøring og README\n\nRepoet fungerer nå fullt og helt til å både enkelt klargjøre et manuskript for\ninnsendelse, og til å lage svar og differanse/endringsdokument på eventuelle reviewer.\n\nMen for å gjøre selve repoet litt mer innbydende er det god praksis å også lage en\nREADME-fil. Med alle releasene vi har laget og artefaktene til de er det enkelt å linke\ntil filer på ulike stadier av prosessen.\n\n_→ Se commit\nb3cbc9d for\nendringene gjort i README.md._\n\nVidere utvidelser\n\nEndringslogg\n\nVi har allerede satt opp en hel del automasjon, men vi kan selvfølgelig fortsette enda\nlenger. Git-Cliff kan settes opp til å skrive til en fil, typisk kalt CHANGELOG.md,\nsom i tillegg til at man har endringer mellom versjoner i hver release, så står hele\nendringsloggen i den fila.\n\nPR-basert versjonering\n\nMan kan også sette opp PR-basert (pull request) versjonering som benytter\nConventional commits til å automatisk\ngenerere nye forslag til releaser. Dette krever en litt større endring i konfigurasjonen\ni GitHub CI/CD.\n\nSikker versjonering av GitHub Actions\n\nSom du kanskje har lagt merke til så er alle actions brukt i GitHub workflow spesifisert\nmed en lang hash, etterfulgt av en kommentar som beskriver hvilken versjon den peker på.\nDette er god praksis fordi, som så vidt nevnt tidligere, Git Tags er \"mutable\"; de kan\nforandres og flyttes på. Dette gjør de til en potensiell angrepsflate, og det er derfor\ntryggere å spesifisere commit hash, siden den er \"immutable\", uforanderlig.\n\nFor å enkelt holde seg oppdatert med de siste versjonene kan man bruke\npinact-action, men denne vil trenge\nen TOKEN med rettigheter til å skrive til .github/workflows-filene.\n\nEnda mer mise-magi\n\nVi har allerede etablert at mise-en-place er en strålende programvare, og den kan gjøre\nenda litt mer. Tre kommandoer som er nyttige for å ha et repo som både er lett å sette\nopp, og har en veldokumentert flyt kan man kjøre\n\nDen første kommandoen skriver en fil med låste versjoner som er tilpasset installasjon\ntil alle vanlige plattformer. Andre kommando genererer et shell-skript som installerer\nsamme versjon av mise-en-place som er i bruk, mens den siste kommandoen genererer\ndokumentasjon for alle tasks som er definert med mise-en-place.\n\n_→ Se commit\n9c1fb30 for filer\nsom legger til funksjonalitet for\nversjonering av actions og\nmise bootstraping._",
"title": "Arbeidsflyt for publisering av artikler"
}