From 737b2fc3f20f84a4e73f557d728bc942a7986239 Mon Sep 17 00:00:00 2001 From: niko Date: Thu, 18 Jun 2026 12:55:02 +0300 Subject: [PATCH] Feature/yksinkertaistetaan raportointi logiikkaa (#22) Co-authored-by: moilanik Reviewed-on: https://gitea.app.keskikuja.site/niko/gitea-ci-library/pulls/22 --- .gitea/scripts/bats-coverage.sh | 48 ++- .gitea/workflows/example-bats-tests.yml | 41 +-- .../workflows/example-build-ci-cucumber.yml | 4 +- .gitea/workflows/example-cucumber-tests.yml | 35 +-- .gitea/workflows/example-feature.yml | 2 - .gitea/workflows/example-main.yml | 2 - Dockerfile.ci-bats | 2 +- README.md | 3 +- scripts/ci-report.sh | 86 ++++++ scripts/publish-git-pages.sh | 37 ++- skills/consumer-pipelines/SKILL.md | 277 ++++++++++++------ 11 files changed, 357 insertions(+), 180 deletions(-) create mode 100644 scripts/ci-report.sh diff --git a/.gitea/scripts/bats-coverage.sh b/.gitea/scripts/bats-coverage.sh index 43c76d9..ce34c87 100755 --- a/.gitea/scripts/bats-coverage.sh +++ b/.gitea/scripts/bats-coverage.sh @@ -1,37 +1,29 @@ #!/usr/bin/env bash set -euo pipefail -WORKSPACE_VOLUME="${1:-}" -REPORT_DIR="${2:-}" +REPORT_DIR="${1:-}" +COVERAGE_DIR="${REPORT_DIR}/coverage" -[ -n "$WORKSPACE_VOLUME" ] || { echo "ERROR: workspace volume name required" >&2; exit 1; } [ -n "$REPORT_DIR" ] || { echo "ERROR: report directory required" >&2; exit 1; } -HAS_COVERAGE=false -COVERAGE_SRC="" -if docker run --rm -v "$WORKSPACE_VOLUME":/data alpine sh -c '[ -d /data/coverage ] && ls -A /data/coverage | grep -q .' 2>/dev/null; then - COVERAGE_SRC="/data/coverage" +if [ -d coverage ]; then + mkdir -p "$COVERAGE_DIR" + cp -a coverage/. "$COVERAGE_DIR/" fi -if [ -n "$COVERAGE_SRC" ]; then - mkdir -p "$REPORT_DIR/coverage" - docker run --rm -v "$WORKSPACE_VOLUME":/data alpine tar c -C "$COVERAGE_SRC" . | tar x -C "$REPORT_DIR/coverage" - HAS_COVERAGE=true +if [ -d "$COVERAGE_DIR" ] && [ ! -f "$COVERAGE_DIR/index.html" ]; then + SHA8="${GITHUB_SHA:0:8}" + { + echo '' + echo "Coverage report ${SHA8}" + echo '' + echo "

Coverage report ${SHA8}

' + } > "$COVERAGE_DIR/index.html" fi - -cat > "$REPORT_DIR/index.html" << EOF - -Bats report ${GITHUB_SHA:0:8} - -

Bats report ${GITHUB_SHA:0:8}

-' >> "$REPORT_DIR/index.html" diff --git a/.gitea/workflows/example-bats-tests.yml b/.gitea/workflows/example-bats-tests.yml index 9557334..b3f8443 100644 --- a/.gitea/workflows/example-bats-tests.yml +++ b/.gitea/workflows/example-bats-tests.yml @@ -6,8 +6,9 @@ on: required: true type: string bats-image: - required: true + required: false type: string + default: gitea.app.keskikuja.site/niko/ci-bats:latest secrets: GITEA_TOKEN: required: true @@ -23,6 +24,8 @@ env: jobs: bats: runs-on: ubuntu-latest + container: + image: ${{ inputs.bats-image }} steps: - uses: actions/checkout@v4 - uses: actions/checkout@v4 @@ -31,34 +34,18 @@ jobs: path: .ci - name: Run bats tests - id: bats-tests - shell: bash run: | - docker volume create bats-workspace - tar c . | docker run --rm -i -v bats-workspace:/data alpine tar x -C /data - mkdir -p "reports/${GITHUB_SHA:0:8}/bats" - set +e - docker run --rm \ - -v bats-workspace:/data \ - --entrypoint bash ${{ inputs.bats-image }} \ - -c 'cd /data && bashcov -- bats tests/' \ - > "reports/${GITHUB_SHA:0:8}/bats/results.txt" 2>&1 - BATS_EXIT=$? - bash .ci/.gitea/scripts/bats-coverage.sh bats-workspace "reports/${GITHUB_SHA:0:8}/bats" - docker volume rm bats-workspace > /dev/null 2>&1 - bash .ci/.gitea/scripts/bats-report.sh "reports/${GITHUB_SHA:0:8}/bats" - echo "BATS_EXIT=${BATS_EXIT}" >> "${GITHUB_ENV}" - exit ${BATS_EXIT} + mkdir -p reports/bats + bashcov -- bats tests/ > reports/bats/results.txt 2>&1 - - name: Publish bats reports + - name: Post-process coverage if: always() - run: bash .ci/scripts/publish-git-pages.sh bats + run: bash .ci/.gitea/scripts/bats-coverage.sh reports/bats - - name: Report status + - name: Post-process test report if: always() - run: | - if [ "${BATS_EXIT}" = "0" ]; then - bash .ci/scripts/report-status.sh success "Link to Bats reports" unit-tests bats - else - bash .ci/scripts/report-status.sh failure "Link to Bats reports" unit-tests bats - fi + run: bash .ci/.gitea/scripts/bats-report.sh reports/bats + + - name: Report + if: always() + run: bash .ci/scripts/ci-report.sh "Bats test report" unit-tests bats diff --git a/.gitea/workflows/example-build-ci-cucumber.yml b/.gitea/workflows/example-build-ci-cucumber.yml index d45c482..5821f2f 100644 --- a/.gitea/workflows/example-build-ci-cucumber.yml +++ b/.gitea/workflows/example-build-ci-cucumber.yml @@ -25,14 +25,14 @@ on: jobs: load-config: - uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@v1 + uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@main secrets: inherit with: config_path: ${{ inputs.config_path }} build-push: needs: [load-config] - uses: niko/gitea-ci-library/.gitea/workflows/ci-container-build-push.yml@v1 + uses: niko/gitea-ci-library/.gitea/workflows/ci-container-build-push.yml@main secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} diff --git a/.gitea/workflows/example-cucumber-tests.yml b/.gitea/workflows/example-cucumber-tests.yml index 88fb68b..d604044 100644 --- a/.gitea/workflows/example-cucumber-tests.yml +++ b/.gitea/workflows/example-cucumber-tests.yml @@ -6,8 +6,9 @@ on: required: true type: string cucumber-node-image: - required: true + required: false type: string + default: gitea.app.keskikuja.site/niko/ci-cucumber:latest secrets: GITEA_TOKEN: required: true @@ -33,36 +34,14 @@ jobs: path: .ci - name: Run cucumber tests - id: cucumber-tests shell: bash run: | - mkdir -p "reports/${GITHUB_SHA:0:8}/cucumber" - set +e + mkdir -p reports/cucumber npx cucumber-js \ - --format json:"reports/${GITHUB_SHA:0:8}/cucumber/report.json" \ - --format html:"reports/${GITHUB_SHA:0:8}/cucumber/index.html" 2>&1 - CUCUMBER_EXIT=$? - echo "CUCUMBER_EXIT=${CUCUMBER_EXIT}" >> "${GITHUB_ENV}" - exit ${CUCUMBER_EXIT} + --format json:reports/cucumber/report.json \ + --format html:reports/cucumber/report.html 2>&1 - - name: Publish cucumber reports - if: always() - run: bash .ci/scripts/publish-git-pages.sh cucumber - - - name: Report status + - name: Report if: always() shell: bash - run: | - if [ "${CUCUMBER_EXIT}" = "0" ]; then - if [ -f "reports/${GITHUB_SHA:0:8}/cucumber/index.html" ]; then - bash .ci/scripts/report-status.sh success "Link to Cucumber reports" acc-tests cucumber - else - bash .ci/scripts/report-status.sh success "Link to Cucumber reports" acc-tests - fi - else - if [ -f "reports/${GITHUB_SHA:0:8}/cucumber/index.html" ]; then - bash .ci/scripts/report-status.sh failure "Link to Cucumber reports" acc-tests cucumber - else - bash .ci/scripts/report-status.sh failure "Link to Cucumber reports" acc-tests - fi - fi + run: bash .ci/scripts/ci-report.sh "Cucumber test report" acc-tests cucumber diff --git a/.gitea/workflows/example-feature.yml b/.gitea/workflows/example-feature.yml index 47d0fd5..42d79b2 100644 --- a/.gitea/workflows/example-feature.yml +++ b/.gitea/workflows/example-feature.yml @@ -20,7 +20,6 @@ jobs: secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} - bats-image: gitea.app.keskikuja.site/niko/ci-bats:latest cucumber: name: Cucumber tests @@ -29,7 +28,6 @@ jobs: secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} - cucumber-node-image: gitea.app.keskikuja.site/niko/ci-cucumber:latest report-summary: name: Report Summary diff --git a/.gitea/workflows/example-main.yml b/.gitea/workflows/example-main.yml index 5cc8c4c..a734123 100644 --- a/.gitea/workflows/example-main.yml +++ b/.gitea/workflows/example-main.yml @@ -29,7 +29,6 @@ jobs: secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} - bats-image: gitea.app.keskikuja.site/niko/ci-bats:latest cucumber: name: Cucumber tests @@ -39,7 +38,6 @@ jobs: secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} - cucumber-node-image: gitea.app.keskikuja.site/niko/ci-cucumber:latest build-push: name: Build & Push Docker diff --git a/Dockerfile.ci-bats b/Dockerfile.ci-bats index 1ca8e17..6c54ae0 100644 --- a/Dockerfile.ci-bats +++ b/Dockerfile.ci-bats @@ -1,3 +1,3 @@ -FROM bats/bats:latest +FROM bats/bats:1.11.0 RUN apk add --no-cache lsof python3 jq curl ruby && \ gem install bashcov -v 3.3.0 diff --git a/README.md b/README.md index e02fb62..a94da3a 100644 --- a/README.md +++ b/README.md @@ -123,8 +123,8 @@ Hae token Giteasta: ```bash GITEA_URL="https://" -GITEA_ACTIONS_TOKEN="" GITEA_ACTIONS_NAMESPACE="gitea-actions" +GITEA_ACTIONS_TOKEN="" ``` ### 3. Tee secret vain init install yhteydessä @@ -158,6 +158,7 @@ helm upgrade --install act-runner gitea/actions \ --set giteaRootURL="$GITEA_URL" \ --set existingSecret=act-runner-token \ --set existingSecretKey=token \ + --set statefulset.replicas=3 \ --set statefulset.runner.tag=1.0.8 \ --set statefulset.dind.tag=29.5.2-dind \ --set-string 'statefulset.runner.config=log: diff --git a/scripts/ci-report.sh b/scripts/ci-report.sh new file mode 100644 index 0000000..9cc1dd7 --- /dev/null +++ b/scripts/ci-report.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +set -euo pipefail + +DESCRIPTION="${1:-}" +CONTEXT="${2:-}" +SUITE="${3:-}" + +[ -n "$DESCRIPTION" ] || { echo "ERROR: description argument required" >&2; exit 1; } +[ -n "$CONTEXT" ] || { echo "ERROR: context argument required" >&2; exit 1; } +[ -n "$SUITE" ] || { echo "ERROR: suite argument required" >&2; exit 1; } + +REPORT_DIR="reports/${SUITE}" + +if [ ! -d "$REPORT_DIR" ]; then + echo "ERROR: $REPORT_DIR not found" >&2 + bash .ci/scripts/report-status.sh failure "$DESCRIPTION" "$CONTEXT" + exit 1 +fi + +FILES=() +while IFS= read -r -d '' f; do + FILES+=("$(basename "$f")") +done < <(find "$REPORT_DIR" -maxdepth 1 -type f ! -name index.html -print0 2>/dev/null || true) + +SUBDIRS=() +while IFS= read -r -d '' d; do + name="${d#$REPORT_DIR/}" + [ -f "$d/index.html" ] && SUBDIRS+=("$name") +done < <(find "$REPORT_DIR" -maxdepth 1 -type d ! -name . -print0 2>/dev/null || true) + +TOTAL=$(( ${#FILES[@]} + ${#SUBDIRS[@]} )) + +if [ "$TOTAL" -eq 0 ]; then + echo "ERROR: no reportable items in $REPORT_DIR" >&2 + bash .ci/scripts/report-status.sh failure "$DESCRIPTION" "$CONTEXT" + exit 1 +fi + +SHA8="${GITHUB_SHA:0:8}" + +humanize() { + local name="$1" + name="${name%.*}" + name="${name//-/ }" + name="${name//_/ }" + echo "${name^}" +} + +generate_index() { + local html + html='' + html+="$DESCRIPTION" + html+='' + html+="

$DESCRIPTION

    " + for f in "${FILES[@]}"; do + html+="
  • $(humanize "$f")
  • " + done + for d in "${SUBDIRS[@]}"; do + html+="
  • ${d^}
  • " + done + html+='
' + printf '%s' "$html" > "$REPORT_DIR/index.html" +} + +STAGED="reports/${SHA8}/${SUITE}" +mkdir -p "$STAGED" + +if [ "$TOTAL" -eq 1 ]; then + cp -a "$REPORT_DIR/." "$STAGED/" + bash .ci/scripts/publish-git-pages.sh "$SUITE" + + if [ ${#FILES[@]} -eq 1 ]; then + ENTRY="${FILES[0]}" + else + ENTRY="${SUBDIRS[0]}/index.html" + fi + URL="${GIT_PAGES_URL}/${GITHUB_REPOSITORY}/reports/${SHA8}/${SUITE}/${ENTRY}" + bash .ci/scripts/report-status.sh success "$DESCRIPTION" "$CONTEXT" "" "$URL" +else + generate_index + cp -a "$REPORT_DIR/." "$STAGED/" + bash .ci/scripts/publish-git-pages.sh "$SUITE" + bash .ci/scripts/report-status.sh success "$DESCRIPTION" "$CONTEXT" "$SUITE" +fi + +rm -rf "$STAGED" diff --git a/scripts/publish-git-pages.sh b/scripts/publish-git-pages.sh index 81228a7..acee12c 100755 --- a/scripts/publish-git-pages.sh +++ b/scripts/publish-git-pages.sh @@ -33,7 +33,42 @@ else fi mkdir -p "$TARGET" cp -a "$REPORT_DIR/." "$TARGET/" -cat > "$WORK/${OWNER}/${REPO}/reports/${SHA8}/.meta" </dev/null || true) + while IFS= read -r -d '' d; do + name=$(basename "$d") + [ -f "$d/index.html" ] && items+=("$name") + done < <(find "$TARGET" -maxdepth 1 -type d ! -name . -print0 2>/dev/null || true) + + if [ ${#items[@]} -gt 1 ]; then + { + echo '' + echo "Test report ${SHA8}" + echo '' + echo "

Test report ${SHA8}

    " + for item in "${items[@]}"; do + label="${item%.*}" + label="${label//-/ }" + label="${label//_/ }" + if [ -f "$TARGET/$item" ]; then + echo "
  • ${label^}
  • " + else + echo "
  • ${label^}
  • " + fi + done + echo '
' + } > "$TARGET/index.html" + fi +fi + +cat > "$TARGET/.meta" <> GITHUB_ENV` -käärettä ei tarvita. ```yaml - name: Run tests shell: bash run: | > results.txt 2>&1 - EXIT=$? - echo "EXIT=${EXIT}" >> "${GITHUB_ENV}" - exit ${EXIT} ``` **Miksi ei pipeä (`| tee`):** @@ -101,8 +99,29 @@ Jokainen testi kaappaa komentonsa exit-koodin eksplisiittisesti: > results.txt 2>&1 ``` -Ilman `EXIT=$?` + `exit ${EXIT}` komento voi feilata mutta job menee läpi vihreänä — `container:`-modessa -shellin käyttäytyminen vaihtelee. +`set -e` ei pelasta pipe-tilanteessa — `|` syö exit-koodin kuten ennenkin. Redirectillä exit-koodi +välittyy luonnollisesti. + +**Yksi asia per step:** Älä koskaan niputa useaa post-process-komentoa samaan `run:`-blockiin. +`bash -e` pysäyttää koko stepin jos yksi komento epäonnistuu — seuraavat jäävät ajamatta. +Käytä erillisiä steppejä `if: always()`:lla, jotta jokainen vaihe ajetaan itsenäisesti: + +```yaml +# VÄÄRIN — jos coverage epäonnistuu, report jää generoimatta +- name: Post-process reports + run: | + bash .ci/.gitea/scripts/bats-coverage.sh reports/bats + bash .ci/.gitea/scripts/bats-report.sh reports/bats + +# OIKEIN — erilliset stepit if: always() +- name: Post-process coverage + if: always() + run: bash .ci/.gitea/scripts/bats-coverage.sh reports/bats + +- name: Post-process test report + if: always() + run: bash .ci/.gitea/scripts/bats-report.sh reports/bats +``` ## 4. Konttipolitiikka @@ -114,44 +133,33 @@ shellin käyttäytyminen vaihtelee. `latest` on näille paras käytäntö, ei kompromissi 3. **Ei koskaan `curl`-latauksia CI-ajon sisällä** — työkalujen asennus CI-stepeissä hidastaa, epäluotettavaa, ja vaikeuttaa toistettavuutta +4. **Konttikuva hallitaan workflow'ssa, ei kutsujassa** — jos workflow vaatii tietyn + konttikuvan, se määritellään oletuksena (`default:`) workflow'n inputissa. + Kutsujan ei tarvitse tietää eikä välittää image-nimeä ellei halua ylikirjoittaa. CI-kontin build-workflow'n template: [skills/ci-container-build/SKILL.md](../ci-container-build/SKILL.md) — sisältää valmiin `ci-container-build-.yml`-pohjan jossa `workflow_dispatch`-tuki manuaaliajoon. ### 4.1 CI-kontin ajaminen jobissa -CI-kontin voi ajaa joko `container:`-direktiivillä (kaikki stepit kontissa) -tai `docker run --rm`:llä stepin sisällä (checkout natiivisti). Molemmat tavat -toimivat. +Ainoa sallittu tapa on `container:`-direktiivi. `docker run` komennolla kontin +käynnistäminen stepin sisällä on anti-pattern. + +**Miksi:** `docker run` erilliskonttina aiheuttaa: +- Tiedostojen jako vaatii erillisen volyyminhallinnan (`docker volume create`) +- Coverage-data jää volyymiin, ei filesystemille → post-process-skriptit eivät löydä sitä +- Ylimääräisiä siirtoja (`tar`, `docker cp`), jotka voivat epäonnistua hiljaa +- Vaikeampi debugata (data on kontissa, ei CWD:ssä) + +`container:`-direktiivillä kaikki ajetaan samassa kontissa — tiedostot ovat suoraan +filesystemillä, post-process-skriptit näkevät ne ilman erillistä siirtoa. ```yaml -# Tapa A: container:-direktiivi jobs: : runs-on: ubuntu-latest container: image: ${{ inputs. }} - steps: - - uses: actions/checkout@v4 - - uses: actions/checkout@v4 - with: - repository: /gitea-ci-library - path: .ci - - name: Run - shell: bash - run: | - mkdir -p "reports/${GITHUB_SHA:0:8}/" - > "reports/${GITHUB_SHA:0:8}//results.txt" 2>&1 - EXIT=$? - echo "EXIT=${EXIT}" >> "${GITHUB_ENV}" - exit ${EXIT} -``` - -```yaml -# Tapa B: docker run --rm stepin sisällä (kuten example-bats-tests.yml) -jobs: - : - runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/checkout@v4 @@ -162,87 +170,179 @@ jobs: - name: Run shell: bash run: | - docker volume create ws- - tar c . | docker run --rm -i -v ws-:/data alpine tar x -C /data - mkdir -p "reports/${GITHUB_SHA:0:8}/" - set +e - docker run --rm \ - -v ws-:/data \ - --entrypoint bash ${{ inputs. }} \ - -c 'cd /data && ' \ - > "reports/${GITHUB_SHA:0:8}//results.txt" 2>&1 - EXIT=$? - docker volume rm ws- > /dev/null 2>&1 - echo "EXIT=${EXIT}" >> "${GITHUB_ENV}" - exit ${EXIT} + mkdir -p "reports/" + > "reports//results.txt" 2>&1 - - name: Publish reports - if: always() - run: bash .ci/scripts/publish-git-pages.sh - - - name: Report status + - name: Post-process reports if: always() run: | - if [ "${EXIT}" = "0" ]; then - bash .ci/scripts/report-status.sh success "" - else - bash .ci/scripts/report-status.sh failure "" - fi + + + - name: Report + if: always() + run: bash .ci/scripts/ci-report.sh "" ``` -**Malli:** `example-bats-tests.yml` (tapa B). +Jos testi tuottaa raportteja suoraan ilman jälkikäsittelyä, Post-process-steppiä ei tarvita. +Jos jälkikäsittely on tarpeen (coverage-siirto, HTML-generointi raa'asta outputista), +se tehdään omassa stepissä `if: always()` — katso tarkemmin [Raporttitasot](#5-raporttitasot). + +**Mallit:** +- `example-cucumber-tests.yml` — ei post-processia +- `example-bats-tests.yml` — post-process coverage + report ## 5. Raporttitasot -Testi tuottaa raportin `reports/${GITHUB_SHA:0:8}//`-hakemistoon. `publish-git-pages.sh` julkaisee sen, -`report-status.sh` linkittää commit-statusin siihen. Molemmat `if: always()`. +Testi tuottaa raportin `reports//`-hakemistoon. Yksi `ci-report.sh`-kutsu hoitaa sekä +julkaisun että commit-statuksen — erillistä Publish + Report Status -kaksivaiheisuutta ei tarvita. -### Taso 1: Pelkkä teksti +### Taso 1: Ei jälkikäsittelyä -Kun testi tuottaa vain stdout/stderr — tallennetaan `results.txt`: +Kun testi tuottaa raportit suoraan (kuten `pytest --html` tai `cucumber-js --format html`): ```yaml - name: Run tests shell: bash run: | - mkdir -p "reports/${GITHUB_SHA:0:8}/" - > "reports/${GITHUB_SHA:0:8}//results.txt" 2>&1 - EXIT=$? - echo "EXIT=${EXIT}" >> "${GITHUB_ENV}" - exit ${EXIT} + mkdir -p "reports/" + -- name: Publish reports +- name: Report if: always() - shell: bash - run: bash .ci/scripts/publish-git-pages.sh + run: bash .ci/scripts/ci-report.sh "" +``` -- name: Report status - if: always() +### Taso 2: Jälkikäsittely tarvitaan + +Kun testi tuottaa raakadataa (stdout, coverage-tiedostot) joka pitää muuntaa tai siirtää +`reports//`-hakemistoon, käytetään Post-process-steppejä. **Jokainen operaatio +omassa stepissään** — älä koskaan niputa useaa post-process-komentoa samaan `run:`-blockiin: + +```yaml +- name: Run tests shell: bash run: | - if [ "${EXIT}" = "0" ]; then - bash .ci/scripts/report-status.sh success "" - else - bash .ci/scripts/report-status.sh failure "" - fi + mkdir -p "reports/" + > "reports//results.txt" 2>&1 + +- name: Post-process coverage + if: always() + run: /coverage/-hakemistoon> + +- name: Post-process test report + if: always() + run: + +- name: Report + if: always() + run: bash .ci/scripts/ci-report.sh "" ``` -### Taso 2: HTML-raportti +**Huomio subdir-sisällöstä:** Jos testi tuottaa dataa alihakemistoon (esim. +coverage `./coverage/`-kansioon), se pitää erikseen SIIRTÄÄ +`reports///`-hakemistoon ennen `ci-report.sh`:n ajoa. +Ilman siirtoa sisältö ei näy index-sivulla, vaikka työkalu tuottaisi sen oikein. +Subdir vaatii lisäksi `index.html`:n, jotta `ci-report.sh` löytää sen. -Kun testi tuottaa strukturoitua dataa (JUnit XML, coverage, tms.) — generoidaan HTML ja `index.html`: +**Miksi:** Gitea Actions käyttää `bash -e`-oletusta. Jos yksi post-process-komento +epäonnistuu (esim. `set -euo pipefail`-skripti), koko stepi pysähtyy eivätkä seuraavat +komennot käynnisty — raportti jää julkaisematta. Erilliset stepit `if: always()` takaavat +että jokainen post-process-vaihe ajetaan itsenäisesti. + +### Monta raportoitavaa tiedostoa + +Kun `reports//`-hakemistossa on useita tiedostoja tai alihakemistoja, +`ci-report.sh` generoi automaattisesti `reports//index.html` jos hakemistossa +on enemmän kuin yksi raportoitava item. ``` -reports/// -├── index.html ← generoitu: linkit alla oleviin -├── results.txt ← testin stdout -├── junit.xml ← testin JUnit XML -output -└── junit.html ← generoitu HTML (xsltproc, tms.) +reports// +├── results.txt ← testin stdout (skannataan FILES) +├── test-report.html ← generoitu HTML (skannataan FILES) +└── / ← alihakemisto (skannataan SUBDIRS) + └── index.html ← VAIN jos tämä on olemassa ``` -`index.html` linkittää kaikkiin raporttitiedostoihin. Selain avaa sen ja navigoi sieltä -yksittäisiin raportteihin. +**Subdir-sääntö:** Alihakemisto näkyy indexissä VAIN jos se sisältää `index.html`:n. +Pelkkä tyhjä subdir ilman `index.html`:ää ei näy — tämä on yleisin syy miksi +jokin raportin osa (kuten coverage) puuttuu indexistä. -## 6. Nimeäminen +## 6. Raportin julkaisukelpoisuus + +`ci-report.sh` päättää onko raportti julkaisukelpoinen skannaamalla +`reports//`-hakemistoa. + +### Mitä skannataan + +| Mitä | Sääntö | +|---|---| +| **Tiedostot (FILES)** | Kaikki `reports//`-juuressa olevat tiedostot paitsi `index.html` | +| **Alihakemistot (SUBDIRS)** | Vain ne, joissa on `index.html` | + +### Julkaisukelpoisuus + +| Tila | Seuraus | +|---|---| +| `FILES + SUBDIRS = 0` | **Failure** — `ci-report.sh` palauttaa virheen, raporttia ei julkaista | +| `FILES + SUBDIRS = 1` | Suora linkki itemiin — ei generoi index-sivua | +| `FILES + SUBDIRS > 1` | Generoi `reports//index.html`-sivun, linkit kaikkiin itemeihin | + +### Esimerkki: coverage-näkymä + +``` +reports//coverage/index.html ← on olemassa +``` + +Coverage-dataa ei siirretä automaattisesti. Testin tai post-process-stepin pitää +siirtää coverage `reports//coverage/`-hakemistoon ja varmistaa että +`index.html` on mukana. Sama periaate pätee mihin tahansa subdir-sisältöön. + +## 7. Debug-ohje: raportti ei näy + +### 1. Aja lokaalisti samalla komennolla kuin CI + +Näet mitä tiedostoja syntyy, mihin ne tulevat ja mikä on työkalun exit-koodi. + +```bash +# Esimerkki +mkdir -p reports/bats +bashcov -- bats tests/ > reports/bats/results.txt 2>&1 +echo "exit: $?" +ls -la reports/bats/ +``` + +### 2. Lisää `echo "DEBUG: ..." >&2` ennen ja jälkeen kriittisen operaation + +Debuggaus stderriin (`>&2`) näkyy CI-logissa eikä häiritse skriptin normaalia outputia. + +```bash +echo "DEBUG: coverage exists? $([ -d coverage ] && echo YES || echo NO)" >&2 +echo "DEBUG: target/index.html exists? $([ -f reports/suite/coverage/index.html ] && echo YES || echo NO)" >&2 +``` + +### 3. Tarkista kutsuparametrit + +Yleisin virhe: skripti odottaa `$1` = X, mutta kutsuja antaa `$1` = Y ja `$2` = X. +Skripti lukee väärän parametrin ja etsii dataa väärästä paikasta. + +### 4. Tarkista tiedostopolut + +1. Onko lähdetiedosto olemassa ennen kopiointia? +2. Onko kohde olemassa kopioinnin jälkeen? +3. Onko `index.html` subdirissä (vaaditaan `ci-report.sh`:lle)? + +Jos vastaus johonkin on "ei" — tiedät mikä pitää korjata. + +### 5. Poista debug-echot kun ongelma on korjattu + +Debug-rivit eivät kuulu tuotantoon. + +### 6. Älä kokeile — debuggaa + +Kokeilu = arvaus. Debuggaus = lisää echo, aja, lue logi, eristä ongelma. +Vasta sitten korjaa. Tämä on nopeampi tie oikeaan ratkaisuun. + +## 8. Nimeäminen Tiedostonimet `.gitea/workflows/`-kansiossa noudattavat yhtenäistä rakennetta, jotta tiedostot löytyvät nopeasti ja niiden rooli on selvillä: @@ -261,7 +361,7 @@ Single repossa `` jätetään pois — tiedostot ovat suoraan `ci-f Monorepossa prefiksi pitää komponentin tiedostot yhdessä: `ls .*` löytää kaikki kerralla. -## 7. Artifact-kuri +## 9. Artifact-kuri Gitea Actionsin `upload-artifact` jättää pysyvän tiedoston. Artifakteja ei käytetä workflow_call:ien väliseen datan siirtoon ellei se ole teknisesti välttämätöntä. @@ -457,8 +557,9 @@ Gitean Settings → Branches → Add Rule: | Skripti | Käyttötarkoitus | |---|---| -| `report-status.sh` | POSTaa commit-statuksen linkillä | -| `publish-git-pages.sh` | Julkaisee raporttihakemiston git-pagesiin | +| `ci-report.sh` | Yhdistetty raportointi: julkaisee git-pagesiin ja asettaa commit-statuksen. Korvaa erilliset `publish-git-pages.sh` + `report-status.sh` -kutsut. Käyttö: `bash .ci/scripts/ci-report.sh "" ` | +| `report-status.sh` | POSTaa commit-statuksen linkillä (kutsutaan `ci-report.sh`:n sisältä) | +| `publish-git-pages.sh` | Julkaisee raporttihakemiston git-pagesiin (kutsutaan `ci-report.sh`:n sisältä) | | `ci-validate.sh` | Validoi `.conf`-tiedoston (kutsutaan `config-provider.yml`:stä) | --- @@ -499,7 +600,7 @@ Ei pipeä (`|`) komennon perässä — se syö exit-koodin. Käytä redirectiä ### Commit-status vain raporttilinkille (ADR 0007) -`report-status.sh`-skriptiä käytetään VAIN kun on raportti linkitettäväksi. +`ci-report.sh`-skriptiä käytetään VAIN kun on raportti linkitettäväksi. Tool-jobit (build, deploy) luottavat Gitean natiiviin job-statukseen. ### Providerin checkout ei kuulu consumerille