Vis prosjektversjonen i et internkontrollfelt på forsiden
test / test (pull_request) Successful in 2m22s

Rapporten bar enok-versjonen og datoen i bunnteksten på hver side, men ikke hvilken versjon
av prosjektet den var laget fra. Det er den opplysningen som knytter rapporten til en bestemt
utgivelse av bygningsmodellen, og den hører hjemme ett sted, tydelig plassert.

Forsiden har nå et internkontrollfelt med prosjekt, prosjektversjon, oppdragsgiver,
energirådgiver, dato og enok-versjon. Bunnteksten gjentar ikke lenger versjon og dato.

Versjonen settes med «rapport.versjon» eller «--versjon», slik at byggeserveren kan sende
taggen på utgivelsen uten at noen fil endres.

Lukker #1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
This commit is contained in:
blandClaude Opus 5 committed 2026-10-05 19:57:21 +02:00
1 parent e6c2efc000
commit bef3bb1090
6 files changed
+152 -4

No files matched your search

+14 -2
View File
@@ -103,7 +103,7 @@ Typst må være installert for PDF-rapporten. Uten Typst kjører du med `--ingen
| `enok klima --kommune Oslo` | Viser nøkkeltall for ett klimasted |
| `enok skala smaahus --areal 140` | Viser karakterskalaen med arealkorreksjon |
Nyttige valg til `beregn`: `--tillegg FIL`, `--ingen-pdf`, `--ingen-timeserie`, `--enova-xml`,
Nyttige valg til `beregn`: `--tillegg FIL`, `--versjon VERSJON`, `--ingen-pdf`, `--ingen-timeserie`, `--enova-xml`,
`--uten-scenarier`, `--ut KATALOG`.
### Utdata
@@ -188,6 +188,18 @@ logo = "logo.svg" # vises øverst på forsiden
farge = "#880000" # aksentfarge i overskrifter og tabeller
avsender = "Firma · Adresse · Org.nr. 000 000 000"
skrift_overskrift = "Futura Now Headline"
versjon = "v1.4.0" # prosjektets versjon, se nedenfor
```
Forsiden har et internkontrollfelt med hvilket prosjekt rapporten hører til, hvilken versjon
av prosjektet den er laget fra, oppdragsgiver og energirådgiver, datoen og hvilken
enok-versjon som regnet den. Opplysningene står der én gang, ikke i bunnteksten på hver side.
Prosjektversjonen settes i `rapport.versjon`, eller med `--versjon` på `beregn`. Da kan
byggeserveren sende taggen på utgivelsen uten at noen fil må endres:
```sh
enok beregn modell.ifc --tillegg prosjekt.toml --versjon "$GITHUB_REF_NAME"
```
Scenarier flettes inn i bygningsbeskrivelsen: tabeller flettes rekursivt, elementer i lister
@@ -425,7 +437,7 @@ jobs:
- name: Lag rapporten
run: |
chmod +x enok
./enok beregn bygning.toml --ut dist
./enok beregn bygning.toml --ut dist --versjon "$GITHUB_REF_NAME"
```
## Kontroll av beregningen
+9 -1
View File
@@ -61,6 +61,10 @@ struct Beregn {
/// Tilleggsfil som flettes inn: det modellen ikke beskriver, og rettelser.
#[arg(short, long, value_name = "FIL")]
tillegg: Option<PathBuf>,
/// Prosjektets versjon, som vises i internkontrollfeltet på forsiden. Overstyrer
/// `rapport.versjon`. Byggeserveren sender gjerne taggen på utgivelsen.
#[arg(long, value_name = "VERSJON")]
versjon: Option<String>,
}
#[derive(Args)]
@@ -174,7 +178,11 @@ fn les_modell(
}
fn beregn(a: Beregn, kilde: &Datakilde) -> Result<()> {
let (bygning, merknader, modell) = les_modell(&a.fil, a.tillegg.as_deref())?;
let (mut bygning, merknader, modell) = les_modell(&a.fil, a.tillegg.as_deref())?;
if let Some(v) = &a.versjon {
bygning.rapport.versjon = Some(v.clone());
}
let bygning = bygning;
for m in &merknader {
eprintln!(" · {m}");
}
+4
View File
@@ -102,6 +102,10 @@ pub struct Rapport {
/// Skrift for overskrifter. Utelatt: enoks egen.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub skrift_overskrift: Option<String>,
/// Prosjektets versjon, typisk taggen på utgivelsen rapporten hører til, for eksempel
/// «v0.3.12». Vises i internkontrollfeltet på forsiden. Kan settes med `--versjon`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub versjon: Option<String>,
}
#[derive(Deserialize, Serialize, Clone, Debug)]
+30 -1
View File
@@ -165,6 +165,35 @@ fn kilde(r: &Resultat, scenarier: &[(String, Resultat)]) -> String {
}
s.push_str(" ]\n)\n\n#v(0.6cm)\n");
// Internkontroll: hvilket prosjekt rapporten hører til, hvilken versjon av det, og
// hva den er laget med. Står på forsiden i stedet for i bunnteksten på hver side.
let mut felter: Vec<(String, String)> = Vec::new();
// Adressen står allerede under tittelen på forsiden.
felter.push(("Prosjekt".into(), l.navn.clone()));
if let Some(v) = &rap.versjon {
felter.push(("Prosjektversjon".into(), v.clone()));
}
if let Some(o) = &b.oppdragsgiver {
felter.push(("Oppdragsgiver".into(), o.clone()));
}
if let Some(ra) = &b.energiraadgiver {
felter.push(("Energirådgiver".into(), ra.clone()));
}
felter.push(("Dato".into(), i_dag()));
felter.push((
"Beregnet med".into(),
format!("enok {}", env!("CARGO_PKG_VERSION")),
));
s.push_str("#internkontroll((\n");
for (navn, verdi) in &felter {
s.push_str(&format!(
" (\"{}\", \"{}\"),\n",
streng(navn),
streng(verdi)
));
}
s.push_str("))\n\n#v(0.6cm)\n");
// Nøkkeltall.
let nøkkel = vec![
("Bygningskategori".to_string(), e(&k.kategorinavn)),
@@ -828,7 +857,7 @@ fn bunntekst(r: &Resultat) -> String {
if let Some(e) = &b.energiraadgiver {
deler.push(e.clone());
}
deler.push(format!("enok {} · {}", env!("CARGO_PKG_VERSION"), i_dag()));
// Versjon og dato står i internkontrollfeltet på forsiden, ikke på hver side.
deler.join(" · ")
}
+69
View File
@@ -0,0 +1,69 @@
//! Kontroll av opplysningene rapporten skal bære: hvilket prosjekt, hvilken versjon og når.
use enok::data::Datakilde;
use enok::{inndata, kjor, rapport};
use std::path::{Path, PathBuf};
fn rapportkilde(versjon: Option<&str>, katalog: &str) -> String {
let mut b = inndata::les_bygning(Path::new("eksempler/referansebygg/smaahus.toml")).unwrap();
b.rapport.versjon = versjon.map(str::to_string);
let r = kjor::kjor(&b, &Datakilde::default()).unwrap();
let ut: PathBuf = std::env::temp_dir().join(katalog);
rapport::typst_ut::skriv(&r, &ut, &[]).unwrap();
std::fs::read_to_string(ut.join("rapport.typ")).unwrap()
}
fn oppsettlinjen(kilde: &str) -> String {
kilde
.lines()
.find(|l| l.starts_with("#show: oppsett.with("))
.unwrap_or_default()
.to_string()
}
/// Prosjektversjonen hører hjemme i internkontrollfeltet på forsiden.
#[test]
fn prosjektversjonen_staar_i_internkontrollfeltet() {
let kilde = rapportkilde(Some("v0.3.12"), "enok-rapport-med-versjon");
assert!(
kilde.contains("#internkontroll(("),
"mangler internkontrollfeltet"
);
assert!(
kilde.contains("(\"Prosjektversjon\", \"v0.3.12\")"),
"mangler prosjektversjonen"
);
assert!(kilde.contains("(\"Prosjekt\","), "mangler prosjektnavnet");
assert!(kilde.contains("(\"Dato\","), "mangler datoen");
assert!(
kilde.contains("(\"Beregnet med\", \"enok "),
"mangler enok-versjonen"
);
}
/// Uten oppgitt versjon står feltet der, men uten en tom versjonslinje.
#[test]
fn uten_versjon_staar_ingen_versjonslinje() {
let kilde = rapportkilde(None, "enok-rapport-uten-versjon");
assert!(kilde.contains("#internkontroll(("));
assert!(
!kilde.contains("Prosjektversjon"),
"skal ikke stå tom versjon"
);
}
/// Versjon og dato skal stå ett sted, på forsiden, ikke på hver eneste side.
#[test]
fn bunnteksten_gjentar_ikke_versjon_og_dato() {
let kilde = rapportkilde(Some("v0.3.12"), "enok-rapport-bunntekst");
let linje = oppsettlinjen(&kilde);
assert!(!linje.is_empty(), "fant ikke oppsettlinjen");
assert!(
!linje.contains("enok "),
"bunnteksten gjentar enok-versjonen: {linje}"
);
assert!(
!linje.contains("v0.3.12"),
"bunnteksten gjentar prosjektversjonen"
);
}
+26
View File
@@ -107,6 +107,32 @@
)[#tekst]
}
// Internkontrollfelt på forsiden: hvilket prosjekt, hvilken versjon og når.
#let internkontroll(rader) = context {
block(
width: 100%,
inset: 9pt,
radius: 4pt,
fill: lys,
stroke: 0.4pt + kantlinje,
stack(
spacing: 6pt,
text(
font: overskriftsskrift(),
size: 7.5pt,
fill: aksent-valgt.get(),
tracking: 0.8pt,
)[INTERNKONTROLL],
..rader.map(rad => grid(
columns: (3.8cm, 1fr),
gutter: 6pt,
text(size: 8.5pt, fill: mid)[#rad.at(0)],
text(size: 8.5pt)[#rad.at(1)],
)),
),
)
}
// Stor karakterrute på forsiden.
#let karakterrute(bokstav, verdi, farge) = {
box(