From 6113f9744c2a4db15ca90313c8253cef0ab6ff58 Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 05:39:12 +0300 Subject: [PATCH 01/10] =?UTF-8?q?ai=20tiedostojen=20p=C3=A4ivitys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ai-context.md | 31 +++++++++++++++++++++++++------ docs/tech-stack.md | 2 +- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/docs/ai-context.md b/docs/ai-context.md index 41dd103..0047e28 100644 --- a/docs/ai-context.md +++ b/docs/ai-context.md @@ -1,6 +1,6 @@ # AI Context: Gitea Actions CI -kirjasto -**Updated**: 2026-06-15 (siivottu, provider/consumer-erottelu valmis) +**Updated**: 2026-06-19 (provider/consumer dual role, Project Skills -aktivointi) ## Project Overview Gitea Actions reusable workflow -kirjasto mikropalveluiden build-, testaus-, @@ -11,8 +11,8 @@ käyttävät kirjastoa `uses:`-direktiivillä. ## Monorepo: kaksi erillistä kokonaisuutta ### 1. Juuri (`gitea-ci-library`) -Provider-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio. -Consumer kutsuu provider-workflowta `uses:`-direktiivillä. +Provider- ja consumer-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio, +ja consumer-esimerkit (dogfood). Consumer kutsuu provider-workflowta `uses:`-direktiivillä. ### 2. `git-pages/` — oma kokonaisuus Helm-chartti Codeberg git-pagesille. Täysin itsenäinen — oma dokumentaatio, @@ -31,8 +31,8 @@ kuuluu `git-pages/docs/`-alle, ei juuren `docs/`-kansioon. | `scripts/` | Provider-skriptit: `report-status.sh`, `publish-git-pages.sh`, `ci-validate.sh` | | `.gitea/scripts/` | **Consumer-skriptit**: `bats-coverage.sh`, `bats-report.sh` | | `docs/` | Arkkitehtuuri, ADRt (0004–0008) | -| `skills/consumer-pipelines/` | Consumer-pipeline-standardit — AI:n pakottavat säännöt consumer-CI:lle | -| `skills/ci-container-build/` | CI-kontin build-workflow'n template — `ci-container-build-push.yml` | +| `skills/consumer-pipelines/` | Consumer-pipeline-standardit (ks. Project Skills). Koskee vain consumer-puolta | +| `skills/ci-container-build/` | CI-kontin build-workflow'n template (ks. Project Skills) | | `docs/adr/` | Architecture Decision Records | | `git-pages/` | Raporttien hostaus (Helm-chartti) | | `tests/` | Bats-testit skripteille | @@ -57,9 +57,28 @@ kuuluu `git-pages/docs/`-alle, ei juuren `docs/`-kansioon. | `example-cucumber-tests.yml` | workflow_call | Hyväksymätestit Cucumberilla, raportit git-pagesiin, status linkillä | | `example-gitea-env.conf` | — | KEY=VALUE config tälle repolle | +## Provider & Consumer Dual Role + +Tämä repo on **yhtä aikaa sekä provider että consumer**. Eri puolilla on eri säännöt: + +- **Provider-puoli**: `.gitea/workflows/*.yml` (pl. `example-*`), `scripts/` — reusable workflowt joita muut projektit kutsuvat. Saa käyttää `docker run` -komentoja (esim. `docker-build-push.yml`). Consumer-pipeline-standardit (`skills/consumer-pipelines/`) eivät koske provideria. +- **Consumer-puoli**: `.gitea/workflows/example-*`, `.gitea/scripts/` — tämän repon oma CI (dogfood), toimii consumer-esimerkkinä. Käyttää `@main`-refiä provider-viittauksissa (sama repo). Noudattaa `skills/consumer-pipelines/`-sääntöjä. +- **Ulkoiset consumerit** käyttävät `@v1`-tagia provider-viittauksissa. + +## Project Skills (skills/) + +Tämä projekti sisältää omia `.ai/skills/`-järjestelmästä riippumattomia skillejä `skills/`-kansiossa. Jokainen alihakemisto sisältää `SKILL.md`:n jossa on `activation-gate`-kenttä. + +**Sääntö:** Uuden tehtävän alussa skannaa `skills/*/SKILL.md` ja arvioi jokaisen `activation-gate` annettua tehtävää vasten. Jos gate matchaa, lataa skill aktiiviseksi ohjeeksi ennen toimenpiteitä. + +| Skill | Gate | Kuvaus | +|---|---|---| +| `skills/consumer-pipelines/` | Consumer-pipeline-muutokset | Consumer-pipeline-standardit: reitittimen puhtaus, exit-koodi, konttipolitiikka, raportointi, nimeäminen. Koskee vain consumer-puolta. | +| `skills/ci-container-build/` | CI-kontin build | CI-kontin build-workflown template ja Dockerfile-ohjeet | + ## Key Technical Decisions -- **Provider & Consumer -malli**: `example-*`-tiedostot ovat consumer-esimerkkejä, provider-workflowt reusableja. ADR 0005. +- **Provider & Consumer -malli**: Tämä repo on sekä provider että consumer. Provider-workflowt reusableja muille, `example-*`-tiedostot tämän repon oma consumer-CI (dogfood). ADR 0005. - **Vain Gitea, vain reusable workflowt**: ei custom actioneita, ei multi-platform - **Commit-status API vain raporttilinkeille**: Tool-jobit luottavat natiiviin. Test-jobit käyttävät API:a koska se on ainoa tapa upottaa raporttilinkki. ADR 0004, 0007. - **Exit-koodi on ainoa onnistumisen mittari**: Ei pipeä, ei tiedostoheuristiikkaa. ADR 0008. diff --git a/docs/tech-stack.md b/docs/tech-stack.md index 94ff569..3c0d2fd 100644 --- a/docs/tech-stack.md +++ b/docs/tech-stack.md @@ -38,4 +38,4 @@ suoraan Gitea UI:ssa. | **Multi-Git-platform** | Vain Gitea — yksi alusta kunnolla (periaate 10) | | **Custom actionit** | Reusable workflow on kevyempi ja natiivimpi (periaate 2) | | **Ulkoinen orkestraattori** | Gitean `needs` + `if` hoitaa ohjauksen | -| **Artifactory/Nexus** | Gitea Packages riittää MVP:ssä | +| **Artifactory/Nexus** | Build & push toimii Docker-standardilla. UI-tason linkitys (`report-summary`) vaatii Nexus/Artifactory-spesifin URL-rakenteen — ei vielä toteutettu, toteutetaan tarvittaessa | -- 2.52.0 From 15e8cdc562944bdf06c329e587028a2527fb19a3 Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 05:39:27 +0300 Subject: [PATCH 02/10] helm chart check version --- .gitea/workflows/check-version.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/check-version.yml b/.gitea/workflows/check-version.yml index 92cf6af..229b1ee 100644 --- a/.gitea/workflows/check-version.yml +++ b/.gitea/workflows/check-version.yml @@ -42,8 +42,10 @@ jobs: RAW_VERSION=$(jq -r '.version' package.json) elif [ -f pom.xml ]; then RAW_VERSION=$(grep -oP '\K[^<]+' pom.xml | head -1) + elif [ -f Chart.yaml ]; then + RAW_VERSION=$(grep -oP '^version:\s*\K\S+' Chart.yaml) else - echo "ERROR: No VERSION file, package.json, or pom.xml found" >&2 + echo "ERROR: No VERSION file, package.json, pom.xml, or Chart.yaml found" >&2 exit 1 fi BASE_VERSION=$(echo "$RAW_VERSION" | cut -d'.' -f1-2) -- 2.52.0 From a731b62a52b6a120796f7f1c6d2f972176a2ca01 Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 07:25:09 +0300 Subject: [PATCH 03/10] helm chart build & push --- .gitea/workflows/check-version.yml | 6 +- .gitea/workflows/git-pages.ci-main.yml | 47 ++ .gitea/workflows/git-pages.gitea-env.conf | 5 + .gitea/workflows/helm-build-push.yml | 97 ++++ guides/helm-registry-setup.md | 113 +++++ skills/consumer-pipelines/REFERENCE.md | 480 +++++++++++++++++++ skills/consumer-pipelines/SKILL.md | 539 ++-------------------- 7 files changed, 782 insertions(+), 505 deletions(-) create mode 100644 .gitea/workflows/git-pages.ci-main.yml create mode 100644 .gitea/workflows/git-pages.gitea-env.conf create mode 100644 .gitea/workflows/helm-build-push.yml create mode 100644 guides/helm-registry-setup.md create mode 100644 skills/consumer-pipelines/REFERENCE.md diff --git a/.gitea/workflows/check-version.yml b/.gitea/workflows/check-version.yml index 229b1ee..f30c35f 100644 --- a/.gitea/workflows/check-version.yml +++ b/.gitea/workflows/check-version.yml @@ -33,6 +33,8 @@ jobs: if [ -n "${VERSION_FILE}" ]; then if echo "${VERSION_FILE}" | grep -q '\.json$'; then RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}") + elif echo "${VERSION_FILE}" | grep -q -E '\.ya?ml$'; then + RAW_VERSION=$(grep -oP '^version:\s*\K\S+' "${VERSION_FILE}") else RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]') fi @@ -42,10 +44,8 @@ jobs: RAW_VERSION=$(jq -r '.version' package.json) elif [ -f pom.xml ]; then RAW_VERSION=$(grep -oP '\K[^<]+' pom.xml | head -1) - elif [ -f Chart.yaml ]; then - RAW_VERSION=$(grep -oP '^version:\s*\K\S+' Chart.yaml) else - echo "ERROR: No VERSION file, package.json, pom.xml, or Chart.yaml found" >&2 + echo "ERROR: No VERSION file, package.json, Chart.yaml or pom.xml found" >&2 exit 1 fi BASE_VERSION=$(echo "$RAW_VERSION" | cut -d'.' -f1-2) diff --git a/.gitea/workflows/git-pages.ci-main.yml b/.gitea/workflows/git-pages.ci-main.yml new file mode 100644 index 0000000..5f5bbd4 --- /dev/null +++ b/.gitea/workflows/git-pages.ci-main.yml @@ -0,0 +1,47 @@ +name: CI Git-Pages Main +on: + push: + branches: + - main + - feature/helm-chart + paths: + - git-pages/** + - .gitea/workflows/helm-build-push.yml + - .gitea/workflows/git-pages.* + workflow_dispatch: + +jobs: + load-config: + name: Load git-pages.gitea-env.conf to pipeline env + uses: niko/gitea-ci-library/.gitea/workflows/config-provider.yml@main + secrets: inherit + with: + config_path: .gitea/workflows/git-pages.gitea-env.conf + + check-version: + name: Check existing artifact + needs: [load-config] + uses: niko/gitea-ci-library/.gitea/workflows/check-version.yml@main + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + + helm-push: + name: Build & Push Helm chart + needs: [load-config, check-version] + if: needs.check-version.outputs.artifact_exists != 'true' + uses: niko/gitea-ci-library/.gitea/workflows/helm-build-push.yml@main + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + version: ${{ needs.check-version.outputs.version }} + chart_path: git-pages + + report-summary: + name: Report Summary + needs: [load-config, helm-push] + if: always() + uses: niko/gitea-ci-library/.gitea/workflows/report-summary.yml@main + with: + env_json: ${{ needs.load-config.outputs.env_json }} + suites: "" diff --git a/.gitea/workflows/git-pages.gitea-env.conf b/.gitea/workflows/git-pages.gitea-env.conf new file mode 100644 index 0000000..c497b13 --- /dev/null +++ b/.gitea/workflows/git-pages.gitea-env.conf @@ -0,0 +1,5 @@ +GITEA_API_URL=https://gitea.app.keskikuja.site +HELM_REGISTRY=gitea.app.keskikuja.site/niko +HELM_UI_URL=https://gitea.app.keskikuja.site/niko/-/packages/container +GIT_TAG_PREFIX=git-pages/ +VERSION_FILE=git-pages/Chart.yaml diff --git a/.gitea/workflows/helm-build-push.yml b/.gitea/workflows/helm-build-push.yml new file mode 100644 index 0000000..1f919e8 --- /dev/null +++ b/.gitea/workflows/helm-build-push.yml @@ -0,0 +1,97 @@ +name: Helm Build & Push +on: + workflow_call: + inputs: + env_json: + required: true + type: string + version: + required: true + type: string + chart_path: + required: false + type: string + default: '.' + secrets: + GITEA_TOKEN: + required: true + HELM_USER: + required: false + HELM_PASSWORD: + required: true + +env: + GITEA_API_URL: ${{ fromJson(inputs.env_json).GITEA_API_URL }} + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + HELM_REGISTRY: ${{ fromJson(inputs.env_json).HELM_REGISTRY || '' }} + HELM_UI_URL: ${{ fromJson(inputs.env_json).HELM_UI_URL || '' }} + GIT_TAG_PREFIX: ${{ fromJson(inputs.env_json).GIT_TAG_PREFIX || '' }} + CHART_PATH: ${{ inputs.chart_path }} + VERSION: ${{ inputs.version }} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-push: + runs-on: ubuntu-latest + container: + image: alpine/helm:3.19.0 + steps: + - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + with: + repository: niko/gitea-ci-library + path: .ci + + - name: Package Helm chart + run: | + helm package "${CHART_PATH}" \ + --version "${VERSION}" \ + --app-version "${VERSION}" \ + --destination /tmp/helm-packages + + - name: Push to OCI registry + env: + HELM_USER: ${{ secrets.HELM_USER || github.actor }} + HELM_PASSWORD: ${{ secrets.HELM_PASSWORD }} + run: | + REGISTRY="${HELM_REGISTRY:?HELM_REGISTRY not set in env.conf}" + echo "$HELM_PASSWORD" | helm registry login "${REGISTRY}" \ + -u "$HELM_USER" \ + --password-stdin + helm push /tmp/helm-packages/*.tgz "oci://${REGISTRY}" + helm registry logout "${REGISTRY}" + + - name: Report status with UI link + if: success() && env.HELM_UI_URL != '' + run: | + CHART_NAME=$(grep '^name:' "${CHART_PATH}/Chart.yaml" | awk '{print $2}') + UI_URL="${HELM_UI_URL}/${CHART_NAME}/${VERSION}" + bash .ci/scripts/report-status.sh success "Helm chart ${VERSION}" ci-helm-build-push "" "$UI_URL" + + tag-commit: + runs-on: ubuntu-latest + needs: [build-push] + steps: + - uses: actions/checkout@v4 + + - name: Create git tag + env: + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + SERVER_URL: ${{ gitea.server_url }} + RUN_NUMBER: ${{ github.run_number }} + SHA: ${{ github.sha }} + run: | + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + "$SERVER_URL/api/v1/repos/${{ github.repository }}/tags" \ + -H "Authorization: token $GITEA_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\": \"${GIT_TAG_PREFIX}${VERSION}\", \"message\": \"Build #$RUN_NUMBER\", \"target\": \"$SHA\"}") + + if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "409" ]; then + exit 0 + else + exit 1 + fi diff --git a/guides/helm-registry-setup.md b/guides/helm-registry-setup.md new file mode 100644 index 0000000..0f526fd --- /dev/null +++ b/guides/helm-registry-setup.md @@ -0,0 +1,113 @@ +# Helm Registry Setup (OCI) + +Pipeline paketoi Helm chartin OCI-artefaktiksi ja pushee sen OCI-rekisteriin. + +--- + +## 1. Konfiguroi `gitea-env.conf` + +``` +# HELM_REGISTRY on muotoa: registry.example.com/org +# +# host+org: registry.example.com/org +# +# Pipeline rakentaa OCI-refin: oci://${HELM_REGISTRY}/:${VERSION} +# (chart-name tulee Chart.yaml:n name-kentästä) + +HELM_REGISTRY=gitea.app.keskikuja.site/niko # PAKOLLINEN — tyhjä ei käy +HELM_UI_URL= # valinnainen — tarkista Giteasta kontin oma UI-osoite, workflow liittää perään /chart-name/VERSION +GIT_TAG_PREFIX=git-pages/ # valinnainen — monorepo-tägäys +VERSION_FILE=git-pages/Chart.yaml # valinnainen — jos Chart.yaml ei rootissa +``` + +| Kenttä | Pakollinen | Kuvaus | +|---|---|---| +| `HELM_REGISTRY` | **kyllä** | Registry host + owner (esim. `gitea.app.site/niko`). **Tyhjä pysäyttää workflow'n.** | +| `HELM_UI_URL` | ei | Base-URL OCI-paketin UI-sivulle (ilman chart-nimeä ja versiota). Osoite riippuu onko paketti linkitetty repoon vai ei — tarkista Giteasta. Workflow liittää perään `/chart-name/VERSION`. Jos tyhjä, commit-statusia ei erikseen aseteta. | +| `GIT_TAG_PREFIX` | ei | Etuliite git-tägille. Pakollinen monorepossa, jotta tagit eivät sekoitu muihin komponentteihin. | +| `VERSION_FILE` | ei | Polku version lähteeseen (Chart.yaml, package.json, VERSION). Oletus: juuren `Chart.yaml`. | + +**OCI-ref = `oci://${HELM_REGISTRY}/:${VERSION}`** +Esim. `oci://gitea.app.keskikuja.site/niko/git-pages:1.2.3` + +Chartin nimi (``) määräytyy `Chart.yaml`-tiedoston `name`-kentästä. + +--- + +## 2. Luo PAT (Personal Access Token) Giteassa + +**Gitea → oma profiili (oikea yläkulma) → Settings → Applications → Manage Access Tokens → Generate New Token** + +Valitse scope: + +| Scope | Pääsy | +|---|---| +| `package` | **Read and Write** | + +> Tämä token toimii salasanana `helm registry login` -komennossa. Muut scopet (kuten `repository`) eivät riitä — konttirekisteri vaatii nimenomaan `package`-scopen. + +Tokenin arvo näytetään **vain kerran** luomisen yhteydessä. Kopioi se talteen. + +--- + +## 3. Tallenna PAT repositoryn Secretsiin + +Nämä ovat kaksi eri paikkaa: +- **Access Tokenit** (User Settings) = missä luot tokenin +- **Repository Secrets** (Repository Settings) = minne talletat sen workflow'n käyttöön + +**Repository → Settings → Actions → Secrets → Add new secret** + +| Secret | Arvo | +|---|---| +| `HELM_PASSWORD` | Edellisessä vaiheessa luotu PAT | + +`HELM_USER`-secretiä **ei tarvita**. Workflow käyttää automaattisesti `${{ github.actor }}` (workflowin käynnistäjä). + +Jos registry vaatii eri käyttäjätunnuksen kuin `github.actor` (esim. Harbor, Artifactory), lisää myös: + +| Secret | Arvo | +|---|---| +| `HELM_USER` | Registryn käyttäjätunnus | + +--- + +## 4. Tarkistuslista ennen ajoa + +- [ ] `HELM_REGISTRY` asetettu `gitea-env.conf`issa +- [ ] (tarvittaessa) `HELM_UI_URL` asetettu — ilman tätä commit-statusia ei erikseen aseteta +- [ ] PAT luotu Giteassa scopella `package` Read and Write +- [ ] `HELM_PASSWORD`-secret tallennettu repositoryn Secretsiin (se PAT) +- [ ] (tarvittaessa) `HELM_USER`-secret — oletus `github.actor` + +--- + +## 5. Esimerkkejä eri polkurakenteista + +### 5a. Hosti + org — Gitea user-taso + +``` +HELM_REGISTRY=gitea.app.keskikuja.site/niko +``` + +- OCI-ref: `oci://gitea.app.keskikuja.site/niko/git-pages:1.2.3` +- Paketti käyttäjän `niko` alla. Linkitys repoon tehdään Gitean UI:sta: paketin sivulta (Package → Settings) → linkitä repositoryyn. +- `HELM_PASSWORD` = Gitea PAT scopella `package` + +### 5b. Hosti + org — Harbor + +``` +HELM_REGISTRY=harbor.example.com/projekti +``` + +- `HELM_USER` = Harbor-käyttäjä +- `HELM_PASSWORD` = Harbor-token + +### 5c. Artifactory + +``` +HELM_REGISTRY=artifactory.example.com/helm-local +``` + +- `HELM_USER` = service account +- `HELM_PASSWORD` = API-token diff --git a/skills/consumer-pipelines/REFERENCE.md b/skills/consumer-pipelines/REFERENCE.md new file mode 100644 index 0000000..773b945 --- /dev/null +++ b/skills/consumer-pipelines/REFERENCE.md @@ -0,0 +1,480 @@ +# Consumer Pipelines — Reference + +Mallipohjat, esimerkit ja konfiguraatiot. Katso säännöt `SKILL.md`:stä. + +## Reititin — täydellinen esimerkki + +```yaml +jobs: + load-config: + uses: /gitea-ci-library/.gitea/workflows/config-provider.yml@v1 + secrets: inherit + + : + needs: [load-config] + uses: ./.gitea/workflows/..yml + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + + : + needs: [load-config] + uses: ./.gitea/workflows/..yml + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + + report-summary: + needs: [load-config, , ] + if: always() + uses: /gitea-ci-library/.gitea/workflows/report-summary.yml@v1 + with: + env_json: ${{ needs.load-config.outputs.env_json }} + suites: +``` + +## CI-kontin build — parametroitu workflow + +CI-kontin build on `workflow_dispatch`-triggeröity job, joka näkyy Gitea Actionsissa kuten Jenkinsin +parametroitu job — käyttäjä antaa inputit UI:sta ennen ajoa. + +```yaml +name: CI Container Build +on: + workflow_dispatch: + inputs: + config_path: + required: true + type: string + default: '.gitea/workflows/.gitea-env.conf' + description: 'Polku .gitea-env.conf-tiedostoon' + dockerfile_path: + required: true + type: string + default: '/Dockerfile.ci-' + description: 'Polku Dockerfileen' + image_name: + required: true + type: string + default: 'ci-' + description: 'Kontin nimi ilman registry-polkua' + tag: + required: true + type: string + default: 'latest' + description: 'Image-tägi' + +jobs: + load-config: + uses: /gitea-ci-library/.gitea/workflows/config-provider.yml@v1 + secrets: inherit + with: + config_path: ${{ inputs.config_path }} + + build-push: + needs: [load-config] + uses: /gitea-ci-library/.gitea/workflows/ci-container-build-push.yml@v1 + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + dockerfile_path: ${{ inputs.dockerfile_path }} + image_name: ${{ inputs.image_name }} + tag: ${{ inputs.tag }} +``` + +### CI-kontin ajaminen testijobissa + +**Ainoa sallittu tapa** consumer-puolella on `container:`-direktiivi. `docker run` komennolla +kontin käynnistäminen stepin sisällä on anti-pattern. `container:`-direktiivillä kaikki stepit +ajetaan samassa kontissa — tiedostot ovat suoraan filesystemillä eikä erillistä +volyyminhallintaa tarvita. + +```yaml +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/" + > "reports//results.txt" 2>&1 + + - name: Post-process reports + if: always() + run: | + + + - name: Report + if: always() + run: bash .ci/scripts/ci-report.sh "" ${{ job.status }} +``` + +**Usean runnerin cache-ongelma:** Jos eri kerroilla käynnistyy eri runnereita, +niillä voi olla eri versio `latest`-imagen digesteistä. Ratkaisuja: +- Rebuildaa kontti ja aja `docker pull ` manuaalisesti kaikilla runnereilla +- Käytä versioitua tagia (`v2`, `v3`, ...) ja päivitä workflow'n default buildauksen jälkeen + +**Mallit:** +- `example-cucumber-tests.yml` — ei post-processia +- `example-bats-tests.yml` — post-process coverage + report + +## Raporttitasot — tarkat YAML-mallit + +### Taso 1: Ei jälkikäsittelyä + +```yaml +- name: Run tests + shell: bash + run: | + mkdir -p "reports/" + + +- name: Report + if: always() + run: bash .ci/scripts/ci-report.sh "" ${{ job.status }} +``` + +### Taso 2: Jälkikäsittely tarvitaan + +```yaml +- name: Run tests + shell: bash + run: | + 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 "" ${{ job.status }} +``` + +### Väärin vs oikein — yksi asia per step + +```yaml +# VÄÄRIN — helm template fail → kubeconform jää ajamatta, report jää tekemättä +- name: Run tests + run: | + helm template ... > /tmp/manifests.yaml + kubeconform ... > results.txt 2>&1 + +# OIKEIN — erilliset stepit +- name: Helm template + run: helm template platform-helm/ -f values.yaml > /tmp/manifests.yaml 2>&1 + +- name: Kubeconform + if: success() + run: | + mkdir -p reports/kubeconform + kubeconform ... > reports/kubeconform/results.txt 2>&1 + +- name: Report + if: always() + run: bash .ci/scripts/ci-report.sh "Helm kubeconform" helm-test kubeconform ${{ job.status }} +``` + +### Väärin vs oikein — post-process + +```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 +``` + +## 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 | + +### Hakemistorakenne + +``` +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 +``` + +### 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. + +**Provider vastuulla:** `ci-report.sh` (provider-skripti) hoitaa sekä hakemistorakenteen +skannauksen, `index.html`-generoinnin että julkaisun git-pagesiin. Consumer tuottaa +vain raakatiedostot `reports//`-hakemistoon — `ci-report.sh` päättää +julkaisukelpoisuuden ja generoi tarvittavan navigaation. + +## Debug-ohje: raportti ei näy + +### 1. Aja lokaalisti samalla komennolla kuin CI + +```bash +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 + +```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. + +### 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)? + +### 5. Poista debug-echot kun ongelma on korjattu + +### 6. Älä kokeile — debuggaa + +Kokeilu = arvaus. Debuggaus = lisää echo, aja, lue logi, eristä ongelma. Vasta sitten korjaa. + +## Konfiguraatiotiedosto (.gitea-env.conf) + +Tiedosto on `key=value`-muotoinen (kuten `.env`). Kommentit ja tyhjät rivit sallittuja. + +### Single repo + +```ini +# .gitea/workflows/gitea-env.conf +GITEA_API_URL=https://gitea.example.com +GIT_PAGES_URL=https://reports.example.com +``` + +### Docker-artifaktin buildaavat projektit + +```ini +DOCKER_REGISTRY=gitea.example.com/myorg +DOCKER_IMAGE_NAME=my-service +DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container +#DOCKERFILE=Dockerfile.platform # valinnainen, oletus Dockerfile +``` + +`DOCKER_UI_URL` ei sisällä image-nimeä — se on puhdas container-registryn osoite. +Image-nimi lisätään automaattisesti URL:iin `docker-build-push.yml`:ssä. + +### Helm-artifaktin buildaavat projektit + +```ini +HELM_REGISTRY=gitea.example.com/myorg +GIT_TAG_PREFIX=git-pages/ +VERSION_FILE=git-pages/Chart.yaml +``` + +| Kenttä | Pakollinen | Kuvaus | +|---|---|---| +| `HELM_REGISTRY` | **kyllä** | Registry host + owner, esim. `gitea.example.com/myorg`. **Tyhjä pysäyttää workflow'n.** | +| `GIT_TAG_PREFIX` | ei | Etuliite git-tägille. Pakollinen monorepossa. | +| `VERSION_FILE` | ei | Polku version lähteeseen. Oletus: juuren `Chart.yaml`. | + +### Salaisuudet (Gitea Settings → Secrets) + +| Secret | Pakollinen | +|---|---| +| `GITEA_TOKEN` | Aina (Gitean sisäinen, automaattisesti saatavilla) | +| `GIT_PAGES_PUBLISH_TOKEN` | Aina | +| `DOCKER_USERNAME` | Vain jos buildaat kontteja | +| `DOCKER_PASSWORD` | Vain jos buildaat kontteja | +| `HELM_USER` | Vain jos pushaat Helm chartin OCI-rekisteriin (oletus `github.actor`) | +| `HELM_PASSWORD` | Vain jos pushaat Helm chartin OCI-rekisteriin | + +## Monorepo + +Monorepossa yhdessä repossa asuu useampi julkaistava komponentti. Jokaiselle komponentille +oma conf-tiedosto `.gitea/workflows/.gitea-env.conf`. + +### Suositus: komponentit omiin juurihakemistoihin + +On suositeltavaa sijoittaa jokaisen komponentin koko lähdekoodi omaan juuritason +hakemistoonsa (`api/`, `frontend/`, `shared/`). Tämä helpottaa `paths:`-filtteröintiä, +pitää komponentit selkeästi erillään, ja tekee repossa navigoinnista suoraviivaista. + +### Ongelmat ja ratkaisut + +| Ongelma | Ratkaisu | +|---|---| +| Monta komponenttia, yksi repo — mikä triggeröi? | `paths:`-filtteri: `push: { paths: ['/**'] }` | +| Jokaisella komponentilla oma versio | `VERSION_FILE=/package.json` confissa | +| Git-tägit sekaisin ellei nimiavaruutta | `GIT_TAG_PREFIX=/` confissa → tägi `/1.2.3` | +| Eri julkaisutahdit | Riippumattomat CI-triggerit, omat versiopolut | + +### Komponenttikohtainen conf + +```ini +# .gitea/workflows/.gitea-env.conf +GITEA_API_URL=https://gitea.example.com +GIT_PAGES_URL=https://reports.example.com +DOCKER_REGISTRY=gitea.example.com/myorg +DOCKER_IMAGE_NAME= +DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container +GIT_TAG_PREFIX=/ +# Jompikumpi — JSON (.version-kenttä) tai plain text: +VERSION_FILE=/package.json +#VERSION_FILE=/VERSION +``` + +### Monorepo reititin + +```yaml +name: CI Main +on: + push: + branches: + - main + paths: + - '/**' + +jobs: + load-config: + uses: /gitea-ci-library/.gitea/workflows/config-provider.yml@v1 + secrets: inherit + with: + config_path: .gitea/workflows/.gitea-env.conf + + check-version: + needs: [load-config] + uses: /gitea-ci-library/.gitea/workflows/check-version.yml@v1 + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + + : + needs: [load-config, check-version] + if: needs.check-version.outputs.artifact_exists != 'true' + uses: ./.gitea/workflows/..yml + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + + build-push: + needs: [load-config, check-version, ] + if: needs.check-version.outputs.artifact_exists != 'true' + uses: /gitea-ci-library/.gitea/workflows/docker-build-push.yml@v1 + secrets: inherit + with: + env_json: ${{ needs.load-config.outputs.env_json }} + version: ${{ needs.check-version.outputs.version }} + + report-summary: + name: Report Summary + needs: [load-config, build-push] + if: always() + uses: /gitea-ci-library/.gitea/workflows/report-summary.yml@v1 + with: + env_json: ${{ needs.load-config.outputs.env_json }} + suites: ' ' +``` + +### Version elinkaari per komponentti + +`GIT_TAG_PREFIX` takaa että eri komponenttien versiohistoria pysyy erillään. +Git-tägi `/0.2.3` ei sekoitu toisen komponentin tägeihin. + +`check-version.yml` suodattaa ja laskee seuraavan patchin vain kyseisen +komponentin etuliitteellä. Idempotenttius toimii komponenttikohtaisesti: +jos commitilla on jo tägi, pipeline skipataan `if: artifact_exists != 'true'`. + +### Mitä EI kannata tehdä monorepossa + +- Älä aja kaikkia komponentteja samasta triggeristä — `paths:` pitää CI:t erillisinä +- Älä käytä samaa versionhallintatiedostoa usealle komponentille +- Älä anna monorepo-parametreja pipeline-overrideina — kaikki kuuluu conf-tiedostoon + +## Versionhallinta + +`check-version.yml` lukee version automaattisesti prioriteettijärjestyksessä: + +| # | Lähde | Formaatti | +|---|---|---| +| 1 | `VERSION_FILE` confissa | Määritelty polku | +| 2 | `VERSION`-tiedosto (root) | Plain text | +| 3 | `package.json` (root) | `.version`-kenttä | +| 4 | `pom.xml` (root) | ``-elementti | + +`major.minor` otetaan tästä. Patch lasketaan automaattisesti git-tageista. +Esim. `VERSION` = `0.2`, tagit = `0.2.0`, `0.2.1` → seuraava `0.2.2`. + +## Branch protection (PR-gate) + +Gitean Settings → Branches → Add Rule: + +- **Branch:** `main` +- **Enable Require Status Checks:** päälle +- **Status checks:** valitse testijobien nimet + +## Provider-rajapinnat — referenssi + +### Workflowt + +| Workflow | Käyttötarkoitus | +|---|---| +| `config-provider.yml` | Lataa + validoi `.conf`, tuottaa `env_json` | +| `check-version.yml` | Tarkistaa onko commit buildattu, laskee version | +| `docker-build-push.yml` | Buildaa + puskea Docker-imagen, tagittaa commitin | +| `helm-build-push.yml` | Paketoi + puskea Helm chartin OCI-rekisteriin, tagittaa commitin | +| `report-summary.yml` | `GITHUB_STEP_SUMMARY`-taulukko raporttilinkeillä (Gitea 1.27+) | + +### Skriptit (kutsutaan `.ci/scripts/`-polun kautta) + +| Skripti | Käyttötarkoitus | +|---|---| +| `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 "" ${{ job.status }}` | +| `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ä) | diff --git a/skills/consumer-pipelines/SKILL.md b/skills/consumer-pipelines/SKILL.md index d4f2c12..9a5fd55 100644 --- a/skills/consumer-pipelines/SKILL.md +++ b/skills/consumer-pipelines/SKILL.md @@ -19,6 +19,8 @@ impact: high Säännöt joilla consumer-projektit rakentavat CI-pipelinejä `gitea-ci-library`-kirjaston päälle. Nämä eivät ole provider-kirjaston sääntöjä — ne kuvaavat miten consumerin kuuluu käyttää kirjastoa oikein. +Katso tarkat mallipohjat ja esimerkit `REFERENCE.md`:stä. + ## 1. Reitittimen puhtaus Reitittimet (`ci-feature.yml`, `ci-main.yml`) eivät sisällä `run:`-steppejä. Ne koostuvat vain: @@ -36,36 +38,7 @@ with: Jokainen job vastaa yhtä loogista testiä tai operaatiota. Reititin on orkestraattori — kaikki suorittava logiikka on omassa `workflow_call`-tiedostossaan. -**Esimerkki:** - -```yaml -jobs: - load-config: - uses: /gitea-ci-library/.gitea/workflows/config-provider.yml@v1 - secrets: inherit - - : - needs: [load-config] - uses: ./.gitea/workflows/..yml - secrets: inherit - with: - env_json: ${{ needs.load-config.outputs.env_json }} - - : - needs: [load-config] - uses: ./.gitea/workflows/..yml - secrets: inherit - with: - env_json: ${{ needs.load-config.outputs.env_json }} - - report-summary: - needs: [load-config, , ] - if: always() - uses: /gitea-ci-library/.gitea/workflows/report-summary.yml@v1 - with: - env_json: ${{ needs.load-config.outputs.env_json }} - suites: -``` +Katso täydellinen esimerkki `REFERENCE.md`:stä. ## 2. Yksi asia per tiedosto @@ -89,310 +62,60 @@ ja exit-koodi välittyy natiivisti. Ylimääräistä `EXIT=$?` + `echo >> GITHUB > results.txt 2>&1 ``` -**Miksi ei pipeä (`| tee`):** +**Miksi ei pipeä (`| tee`):** `|` syö exit-koodin. Käytä redirectiä `>`. -```bash -# VÄÄRIN — pipe syö exit-koodin - | tee results.txt - -# OIKEIN — redirect tiedostoon - > results.txt 2>&1 -``` - -`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 komentoa samaan `run:`-blockiin — oli kyse -sitten post-processista tai testi- / tarkistusvaiheista. `bash -e` pysäyttää koko stepin -ensimmäisellä failaavalla komennolla, ja loput jäävät ajamatta. - -```yaml -# VÄÄRIN — helm template fail → kubeconform jää ajamatta, report jää tekemättä -- name: Run tests - run: | - helm template ... > /tmp/manifests.yaml - kubeconform ... > results.txt 2>&1 - -# OIKEIN — erilliset stepit -- name: Helm template - run: helm template platform-helm/ -f values.yaml > /tmp/manifests.yaml 2>&1 - -- name: Kubeconform - if: success() - run: | - mkdir -p reports/kubeconform - kubeconform ... > reports/kubeconform/results.txt 2>&1 - -- name: Report - if: always() - run: bash .ci/scripts/ci-report.sh "Helm kubeconform" helm-test kubeconform ${{ job.status }} -``` - -Sama pätee post-process-steppeihin. Älä koskaan niputa useaa post-process-komentoa -samaan `run:`-blockiin. 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 -``` +**Yksi asia per step:** Älä koskaan niputa useaa komentoa samaan `run:`-blockiin. `bash -e` pysäyttää +koko stepin ensimmäisellä failaavalla komennolla, ja loput jäävät ajamatta. Sama pätee post-process-steppeihin. ## 4. Konttipolitiikka 1. **Julkiset registry-kontit kiinteällä versiolla** — `alpine/helm:3.19.0`, `node:22`, `maven:3.9-eclipse-temurin-21`. - Toistettavuus ja turvallisuus eivät saa riippua ulkoisesta `latest`:sta + Toistettavuus ja turvallisuus eivät saa riippua ulkoisesta `latest`:sta. 2. **Projektin omat CI-kontit `latest`-tägillä** — buildattu `ci-container-build-.yml`:llä. Kontin build-pipeline päivittää `latest`:n automaattisesti. Rebuild = käyttöönotto kaikissa pipelineissa ilman versioviittauksien päivittelyä. - `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 + 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. +CI-kontin build-workflow'n template: `skills/ci-container-build/SKILL.md`. ### 4.1 CI-kontin ajaminen jobissa 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 -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/" - > "reports//results.txt" 2>&1 - - - name: Post-process reports - if: always() - run: | - - - - name: Report - if: always() - run: bash .ci/scripts/ci-report.sh "" ${{ job.status }} -``` +Katso CI-kontin template `REFERENCE.md`:stä. **Huomio `actions/checkout@v4`:stä:** `container:`-direktiivillä kaikki stepit ajetaan kontin *sisällä* — myös `actions/checkout@v4`. Se on JavaScript-action -joka vaatii sekä `nodejs` että `git`. Ilman kumpaa tahansa checkout feilaa -`exit 127`. - -```dockerfile -# Varmista että kontissa on nodejs + git -RUN apk add --no-cache nodejs git -``` - -**Tarkista siis aina** että CI-kontin Dockerfilessä on sekä `nodejs` että `git` -asennettuna. Sama pätee mihin tahansa konttiin jota käytetään `container:`-direktiivillä. - -**Usean runnerin cache-ongelma:** Jos eri kerroilla käynnistyy eri runnereita, -niillä voi olla eri versio `latest`-imagen digesteistä. Tämä on `latest`-tagin -tunnettu ongelma. Ratkaisuja: -- Rebuildaa kontti ja aja `docker pull ` manuaalisesti kaikilla - runnereilla -- Käytä versioitua tagia (`v2`, `v3`, ...) ja päivitä workflow'n default - buildauksen jälkeen - -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 +joka vaatii sekä `nodejs` että `git`. Varmista että CI-kontin Dockerfilessä on molemmat. ## 5. Raporttitasot Testi tuottaa raportin `reports//`-hakemistoon. Yksi `ci-report.sh`-kutsu hoitaa sekä -julkaisun että commit-statuksen — erillistä Publish + Report Status -kaksivaiheisuutta ei tarvita. +julkaisun että commit-statuksen. ### Taso 1: Ei jälkikäsittelyä Kun testi tuottaa raportit suoraan (kuten `pytest --html` tai `cucumber-js --format html`): - -```yaml -- name: Run tests - shell: bash - run: | - mkdir -p "reports/" - - -- name: Report - if: always() - run: bash .ci/scripts/ci-report.sh "" ${{ job.status }} -``` +- testi kirjoittaa `reports//`-hakemistoon +- `ci-report.sh` julkaisee ja asettaa commit-statuksen ### 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: +`reports//`-hakemistoon. **Jokainen operaatio omassa stepissään** `if: always()`. -```yaml -- name: Run tests - shell: bash - run: | - 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 "" ${{ job.status }} -``` - -**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. - -**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// -├── results.txt ← testin stdout (skannataan FILES) -├── test-report.html ← generoitu HTML (skannataan FILES) -└── / ← alihakemisto (skannataan SUBDIRS) - └── index.html ← VAIN jos tämä on olemassa -``` +Tarkat YAML-mallit molemmista tasoista: `REFERENCE.md`. **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. Raportin julkaisukelpoisuus +## 6. Nimeäminen -`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ä: +Tiedostonimet `.gitea/workflows/`-kansiossa noudattavat yhtenäistä rakennetta: ``` .ci-feature.yml ← feature-haaran reititin @@ -402,216 +125,35 @@ tiedostot löytyvät nopeasti ja niiden rooli on selvillä: .gitea-env.conf ← komponenttikohtainen konfiguraatio ``` -Single repossa `` jätetään pois — tiedostot ovat suoraan `ci-feature.yml`, -`ci-main.yml`, `.yml`, `ci-container-build-.yml`. +Single repossa `` jätetään pois. +Monorepossa prefiksi pitää komponentin tiedostot yhdessä. -Monorepossa prefiksi pitää komponentin tiedostot yhdessä: `ls .*` löytää kaikki -kerralla. - -## 9. Artifact-kuri +## 7. 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ä. +`workflow_call`:ien väliseen datan siirtoon ellei se ole teknisesti välttämätöntä. **Ensisijainen ratkaisu:** jokainen testi tuottaa tarvitsemansa datan itse. Ei `upload-artifact` + `download-artifact` -riippuvuuksia. -```yaml -# OIKEIN — molemmat testit tuottavat oman datansa -- name: Prepare data - run: > /tmp/data -- name: Validate data - run: /tmp/data -``` +## 8. Report-Summary — pakollinen jokaisen pipelinen lopuksi -**Miksi:** -- Testit pysyvät itsenäisinä — yhden testin fail ei estä muita -- Ei "artifact expired" -virheitä myöhemmin -- Ei pysyviä artifakteja siivoamatta +Jokaisen reitittimen (oli se `ci-main.yml`, `ci-feature.yml` tai mikä tahansa) viimeinen job on `report-summary`. ---- +**Säännöt:** +- `needs:` sisältää **kaikki edeltävät jobit** — summary odottaa että kaikki on valmis (onnistui tai ei) +- `if: always()` — ajetaan aina, vaikka pipeline olisi keskeytetty tai joku jobi failannut +- `suites:` on välilyönnein eroteltu lista suiten nimistä (esim. `bats cucumber`). Tyhjä merkkijono sallittu jos testisuiteja ei ole. +- Provider (`report-summary.yml`) hoitaa summaryn logiikan — reititin vain kutsuu -## Konfiguraatiotiedosto (.gitea-env.conf) +**Miksi aina:** +- Gitea 1.27+ näyttää `GITHUB_STEP_SUMMARY`:n Actions UI:ssa. Ilman summarya pipeline näyttää epätäydelliseltä. +- Summaryyn voidaan myöhemmin lisätä muutakin kuin testilinkkejä (build-artefaktit, deploy-tiedot). +- Yhtenäinen rakenne jokaisessa pipeline-parissa vähentää kysymyksiä. -Tiedosto on `key=value`-muotoinen (kuten `.env`). Kommentit ja tyhjät rivit sallittuja. +YAML-malli: `REFERENCE.md`. -### Single repo - -```ini -# .gitea/workflows/gitea-env.conf -GITEA_API_URL=https://gitea.example.com -GIT_PAGES_URL=https://reports.example.com -``` - -### Docker-artifaktin buildaavat projektit - -```ini -DOCKER_REGISTRY=gitea.example.com/myorg -DOCKER_IMAGE_NAME=my-service -DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container -#DOCKERFILE=Dockerfile.platform # valinnainen, oletus Dockerfile -``` - -`DOCKER_UI_URL` ei sisällä image-nimeä — se on puhdas container-registryn osoite. -Image-nimi lisätään automaattisesti URL:iin `docker-build-push.yml`:ssä. - -### Salaisuudet (Gitea Settings → Secrets) - -| Secret | Pakollinen | -|---|---| -| `GITEA_TOKEN` | Aina (Gitean sisäinen, automaattisesti saatavilla) | -| `GIT_PAGES_PUBLISH_TOKEN` | Aina | -| `DOCKER_USERNAME` | Vain jos buildaat kontteja | -| `DOCKER_PASSWORD` | Vain jos buildaat kontteja | - ---- - -## Monorepo - -Monorepossa yhdessä repossa asuu useampi julkaistava komponentti. Jokaiselle komponentille -oma conf-tiedosto `.gitea/workflows/.gitea-env.conf`, jossa on kaikki -komponenttikohtainen tieto. - -### Suositus: komponentit omiin juurihakemistoihin - -On suositeltavaa sijoittaa jokaisen komponentin koko lähdekoodi omaan juuritason -hakemistoonsa (`api/`, `frontend/`, `shared/`). Tämä helpottaa `paths:`-filtteröintiä, -pitää komponentit selkeästi erillään, ja tekee repossa navigoinnista suoraviivaista. -Tämä on kuitenkin vain suositus — ei pakottava sääntö. - -### Ongelmat ja ratkaisut - -| Ongelma | Ratkaisu | -|---|---| -| Monta komponenttia, yksi repo — mikä triggeröi? | `paths:`-filtteri: `push: { paths: ['/**'] }` | -| Jokaisella komponentilla oma versio | `VERSION_FILE=/package.json` confissa | -| Git-tägit sekaisin ellei nimiavaruutta | `GIT_TAG_PREFIX=/` confissa → tägi `/1.2.3` | -| Eri julkaisutahdit | Riippumattomat CI-triggerit, omat versiopolut | - -### Komponenttikohtainen conf - -```ini -# .gitea/workflows/.gitea-env.conf -GITEA_API_URL=https://gitea.example.com -GIT_PAGES_URL=https://reports.example.com -DOCKER_REGISTRY=gitea.example.com/myorg -DOCKER_IMAGE_NAME= -DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container -GIT_TAG_PREFIX=/ -# Jompikumpi — JSON (.version-kenttä) tai plain text: -VERSION_FILE=/package.json -#VERSION_FILE=/VERSION -``` - -### Monorepo reititin - -```yaml -name: CI Main -on: - push: - branches: - - main - paths: - - '/**' - -jobs: - load-config: - uses: /gitea-ci-library/.gitea/workflows/config-provider.yml@v1 - secrets: inherit - with: - config_path: .gitea/workflows/.gitea-env.conf - - check-version: - needs: [load-config] - uses: /gitea-ci-library/.gitea/workflows/check-version.yml@v1 - secrets: inherit - with: - env_json: ${{ needs.load-config.outputs.env_json }} - - : - needs: [load-config, check-version] - if: needs.check-version.outputs.artifact_exists != 'true' - uses: ./.gitea/workflows/..yml - secrets: inherit - with: - env_json: ${{ needs.load-config.outputs.env_json }} - - build-push: - needs: [load-config, check-version, ] - if: needs.check-version.outputs.artifact_exists != 'true' - uses: /gitea-ci-library/.gitea/workflows/docker-build-push.yml@v1 - secrets: inherit - with: - env_json: ${{ needs.load-config.outputs.env_json }} - version: ${{ needs.check-version.outputs.version }} -``` - -### Version elinkaari per komponentti - -`GIT_TAG_PREFIX` takaa että eri komponenttien versiohistoria pysyy erillään. -Git-tägi `/0.2.3` ei sekoitu toisen komponentin tägeihin. - -`check-version.yml` suodattaa ja laskee seuraavan patchin vain kyseisen -komponentin etuliitteellä. Idempotenttius toimii komponenttikohtaisesti: -jos commitilla on jo tägi, pipeline skipataan `if: artifact_exists != 'true'`. - -### Mitä EI kannata tehdä monorepossa - -- Älä aja kaikkia komponentteja samasta triggeristä — `paths:` pitää CI:t erillisinä -- Älä käytä samaa versionhallintatiedostoa usealle komponentille -- Älä anna monorepo-parametreja pipeline-overrideina — kaikki kuuluu conf-tiedostoon - ---- - -## Versionhallinta - -`check-version.yml` lukee version automaattisesti prioriteettijärjestyksessä: - -| # | Lähde | Formaatti | -|---|---|---| -| 1 | `VERSION_FILE` confissa | Määritelty polku | -| 2 | `VERSION`-tiedosto (root) | Plain text | -| 3 | `package.json` (root) | `.version`-kenttä | -| 4 | `pom.xml` (root) | ``-elementti | - -`major.minor` otetaan tästä. Patch lasketaan automaattisesti git-tageista. -Esim. `VERSION` = `0.2`, tagit = `0.2.0`, `0.2.1` → seuraava `0.2.2`. - ---- - -## Branch protection (PR-gate) - -Gitean Settings → Branches → Add Rule: - -- **Branch:** `main` -- **Enable Require Status Checks:** päälle -- **Status checks:** valitse testijobien nimet - ---- - -## Provider-rajapinnat — referenssi - -### Workflowt - -| Workflow | Käyttötarkoitus | -|---|---| -| `config-provider.yml` | Lataa + validoi `.conf`, tuottaa `env_json` | -| `check-version.yml` | Tarkistaa onko commit buildattu, laskee version | -| `docker-build-push.yml` | Buildaa + puskea Docker-imagen, tagittaa commitin | -| `report-summary.yml` | `GITHUB_STEP_SUMMARY`-taulukko raporttilinkeillä (Gitea 1.27+) | - -### Skriptit (kutsutaan `.ci/scripts/`-polun kautta) - -| Skripti | Käyttötarkoitus | -|---|---| -| `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 "" ${{ job.status }}` | -| `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ä) | - ---- - -## ADR-yhteenveto — consumerin kannalta oleelliset säännöt +## 9. ADR-yhteenveto — consumerin kannalta oleelliset säännöt ### Reititin ei sisällä suorittavaa koodia (ADR 0010) @@ -631,25 +173,18 @@ sisäiseen dogfood-käyttöön. Breaking changet kielletty — `v1`-rajapinta on ### Paikalliset `uses:` eivät käytä refiä Gitea act runner v1.0.8 muodostaa paikallisista `uses: ./.gitea/workflows/*.yml@main`-viittauksista -epävalidin git-refin `main@`, joka aiheuttaa virheen `Revision invalid : reference must -be defined once at the beginning`. +epävalidin git-refin `main@`. Paikallisista `uses:`-direktiiveistä EI koskaan käytetä `@main`- tai muuta ref-päätettä: - `uses: ./.gitea/workflows/chart.helm-lint.yml` ← oikein - `uses: ./.gitea/workflows/chart.helm-lint.yml@main` ← väärin -Ilman refiä runner käyttää workflow'ta triggeröivästä commitista. Ulkoisten repojen -viittauksissa (`niko/...@v1`) pääte pysyy. Nämä resolvoidaan eri reittiä ja toimivat oikein. +Ilman refiä runner käyttää workflow'ta triggeröivästä commitista. ### Exit-koodi on ainoa onnistumisen mittari (ADR 0008) Ei pipeä (`|`) komennon perässä — se syö exit-koodin. Käytä redirectiä (`> file 2>&1`). -### Commit-status vain raporttilinkille (ADR 0007) - -`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 Providerin scriptit haetaan `actions/checkout`-stepillä `.ci/`-polkuun. -- 2.52.0 From 9400815a01eb377e70e24d17006a652b57dfc22a Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 07:43:02 +0300 Subject: [PATCH 04/10] check version script tiedostoon --- .gitea/workflows/check-version.yml | 57 +++++------------------------ scripts/check-version.sh | 59 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 48 deletions(-) create mode 100755 scripts/check-version.sh diff --git a/.gitea/workflows/check-version.yml b/.gitea/workflows/check-version.yml index f30c35f..f638b08 100644 --- a/.gitea/workflows/check-version.yml +++ b/.gitea/workflows/check-version.yml @@ -27,56 +27,17 @@ jobs: version: ${{ steps.set-outputs.outputs.version }} steps: - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + with: + repository: niko/gitea-ci-library + path: .ci - name: Check existing artifact and calculate version - run: | - if [ -n "${VERSION_FILE}" ]; then - if echo "${VERSION_FILE}" | grep -q '\.json$'; then - RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}") - elif echo "${VERSION_FILE}" | grep -q -E '\.ya?ml$'; then - RAW_VERSION=$(grep -oP '^version:\s*\K\S+' "${VERSION_FILE}") - else - RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]') - fi - elif [ -f VERSION ]; then - RAW_VERSION=$(cat VERSION | tr -d '[:space:]') - elif [ -f package.json ]; then - RAW_VERSION=$(jq -r '.version' package.json) - elif [ -f pom.xml ]; then - RAW_VERSION=$(grep -oP '\K[^<]+' pom.xml | head -1) - else - echo "ERROR: No VERSION file, package.json, Chart.yaml or pom.xml found" >&2 - exit 1 - fi - BASE_VERSION=$(echo "$RAW_VERSION" | cut -d'.' -f1-2) - echo "gitea-ci-library - Tunnistettu Major.Minor versio: $BASE_VERSION" - - TAGS_JSON=$(curl -s -f -H "Authorization: token $GITEA_TOKEN" \ - "${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/tags") - - TAG=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX}" ' - if type == "array" then - .[] | select(.commit.sha == "${{ github.sha }}" and (.name | startswith($prefix))) | .name - else empty end' | head -1) - - mkdir -p /tmp/build-ctx - - if [ -n "$TAG" ]; then - echo "ARTIFACT_EXISTS=true" > /tmp/build-ctx/build.env - echo "NEXT_VERSION=$TAG" >> /tmp/build-ctx/build.env - echo "gitea-ci-library - Artefakti löytyi jo tagilla: $TAG." - else - echo "ARTIFACT_EXISTS=false" > /tmp/build-ctx/build.env - - HIGHEST_PATCH=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX}" --arg bv "${GIT_TAG_PREFIX}${BASE_VERSION}." ' - if type == "array" then .[] | .name | select(startswith($bv)) | sub($bv; "") | tonumber else empty end' | sort -rn | head -1) - - if [ -z "$HIGHEST_PATCH" ]; then NEXT_PATCH=0; else NEXT_PATCH=$((HIGHEST_PATCH + 1)); fi - FULL_VERSION="${BASE_VERSION}.${NEXT_PATCH}" - - echo "NEXT_VERSION=$FULL_VERSION" >> /tmp/build-ctx/build.env - echo "gitea-ci-library - Uusi vapaa versio: $FULL_VERSION" - fi + env: + SERVER_URL: ${{ gitea.server_url }} + REPO: ${{ github.repository }} + SHA: ${{ github.sha }} + run: bash .ci/scripts/check-version.sh - name: Set job outputs id: set-outputs diff --git a/scripts/check-version.sh b/scripts/check-version.sh new file mode 100755 index 0000000..ba05d8d --- /dev/null +++ b/scripts/check-version.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +set -e + +RAW_VERSION="" + +if [ -n "${VERSION_FILE}" ] && [ -f "${VERSION_FILE}" ]; then + if echo "${VERSION_FILE}" | grep -q -E '\.json$'; then + RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}") + elif echo "${VERSION_FILE}" | grep -q -E '\.(ya?ml)$'; then + RAW_VERSION=$(grep -oP '^version:\s*\K\S+' "${VERSION_FILE}") + else + RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]') + fi +fi + +if [ -z "${RAW_VERSION}" ]; then + if [ -f VERSION ]; then + RAW_VERSION=$(cat VERSION | tr -d '[:space:]') + elif [ -f package.json ]; then + RAW_VERSION=$(jq -r '.version' package.json) + elif [ -f pom.xml ]; then + RAW_VERSION=$(grep -oP '\K[^<]+' pom.xml | head -1) + elif [ -f Chart.yaml ]; then + RAW_VERSION=$(grep -oP '^version:\s*\K\S+' Chart.yaml) + else + echo "ERROR: No version source found (VERSION_FILE, VERSION, package.json, pom.xml, Chart.yaml)" >&2 + exit 1 + fi +fi + +BASE_VERSION=$(echo "$RAW_VERSION" | cut -d'.' -f1-2) +echo "gitea-ci-library - Tunnistettu Major.Minor versio: $BASE_VERSION" + +TAGS_JSON=$(curl -s -f -H "Authorization: token ${GITEA_TOKEN}" \ + "${SERVER_URL}/api/v1/repos/${REPO}/tags") + +TAG=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX}" --arg sha "${SHA}" ' + if type == "array" then + .[] | select(.commit.sha == $sha and (.name | startswith($prefix))) | .name + else empty end' | head -1) + +mkdir -p /tmp/build-ctx + +if [ -n "$TAG" ]; then + echo "ARTIFACT_EXISTS=true" > /tmp/build-ctx/build.env + echo "NEXT_VERSION=$TAG" >> /tmp/build-ctx/build.env + echo "gitea-ci-library - Artefakti löytyi jo tagilla: $TAG." +else + echo "ARTIFACT_EXISTS=false" > /tmp/build-ctx/build.env + + HIGHEST_PATCH=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX}" --arg bv "${GIT_TAG_PREFIX}${BASE_VERSION}." ' + if type == "array" then .[] | .name | select(startswith($bv)) | sub($bv; "") | tonumber else empty end' | sort -rn | head -1) + + if [ -z "$HIGHEST_PATCH" ]; then NEXT_PATCH=0; else NEXT_PATCH=$((HIGHEST_PATCH + 1)); fi + FULL_VERSION="${BASE_VERSION}.${NEXT_PATCH}" + + echo "NEXT_VERSION=$FULL_VERSION" >> /tmp/build-ctx/build.env + echo "gitea-ci-library - Uusi vapaa versio: $FULL_VERSION" +fi -- 2.52.0 From ca569e280f06cb31dfdc219e39bba5c9c1312403 Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 07:43:36 +0300 Subject: [PATCH 05/10] trigger helm --- git-pages/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-pages/README.md b/git-pages/README.md index 9b47223..321b7ed 100644 --- a/git-pages/README.md +++ b/git-pages/README.md @@ -68,7 +68,7 @@ open "https://gitea.app.keskikuja.site/${REPO_OWNER}/${REPO_NAME}/settings/actio > 💡 **Monelle repoille:** Toista vaiheet 3–4, tai katso [automatisointi](docs/secrets.md#automatisointi-useamman-repon-salaisuuden-lis%C3%A4%C3%A4miseen). ---- +--- ## Käyttöönotto -- 2.52.0 From a40a7703f047ee10ec02dd79e8ce7a7209dd6d6f Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 07:55:30 +0300 Subject: [PATCH 06/10] check version testit --- git-pages/README.md | 2 +- scripts/check-version.sh | 15 +- tests/check-version.bats | 170 ++++++++++++++++++ tests/fixtures/check-version/Chart.yaml | 6 + tests/fixtures/check-version/VERSION | 1 + tests/fixtures/check-version/package.json | 1 + tests/fixtures/check-version/pom.xml | 1 + .../fixtures/check-version/subdir/Chart.yaml | 6 + 8 files changed, 194 insertions(+), 8 deletions(-) create mode 100644 tests/check-version.bats create mode 100644 tests/fixtures/check-version/Chart.yaml create mode 100644 tests/fixtures/check-version/VERSION create mode 100644 tests/fixtures/check-version/package.json create mode 100644 tests/fixtures/check-version/pom.xml create mode 100644 tests/fixtures/check-version/subdir/Chart.yaml diff --git a/git-pages/README.md b/git-pages/README.md index 321b7ed..9b47223 100644 --- a/git-pages/README.md +++ b/git-pages/README.md @@ -68,7 +68,7 @@ open "https://gitea.app.keskikuja.site/${REPO_OWNER}/${REPO_NAME}/settings/actio > 💡 **Monelle repoille:** Toista vaiheet 3–4, tai katso [automatisointi](docs/secrets.md#automatisointi-useamman-repon-salaisuuden-lis%C3%A4%C3%A4miseen). ---- +--- ## Käyttöönotto diff --git a/scripts/check-version.sh b/scripts/check-version.sh index ba05d8d..6adcf77 100755 --- a/scripts/check-version.sh +++ b/scripts/check-version.sh @@ -4,12 +4,13 @@ set -e RAW_VERSION="" if [ -n "${VERSION_FILE}" ] && [ -f "${VERSION_FILE}" ]; then - if echo "${VERSION_FILE}" | grep -q -E '\.json$'; then - RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}") - elif echo "${VERSION_FILE}" | grep -q -E '\.(ya?ml)$'; then - RAW_VERSION=$(grep -oP '^version:\s*\K\S+' "${VERSION_FILE}") - else - RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]') + RAW_VERSION=$(sed -n 's/^version:[[:space:]]*\([^[:space:]]*\).*/\1/p' "${VERSION_FILE}") + if [ -z "${RAW_VERSION}" ]; then + if echo "${VERSION_FILE}" | grep -q -E '\.json$'; then + RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}") + else + RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]') + fi fi fi @@ -21,7 +22,7 @@ if [ -z "${RAW_VERSION}" ]; then elif [ -f pom.xml ]; then RAW_VERSION=$(grep -oP '\K[^<]+' pom.xml | head -1) elif [ -f Chart.yaml ]; then - RAW_VERSION=$(grep -oP '^version:\s*\K\S+' Chart.yaml) + RAW_VERSION=$(sed -n 's/^version:[[:space:]]*\([^[:space:]]*\).*/\1/p' Chart.yaml) else echo "ERROR: No version source found (VERSION_FILE, VERSION, package.json, pom.xml, Chart.yaml)" >&2 exit 1 diff --git a/tests/check-version.bats b/tests/check-version.bats new file mode 100644 index 0000000..6618e94 --- /dev/null +++ b/tests/check-version.bats @@ -0,0 +1,170 @@ +#!/usr/bin/env bats + +source "$BATS_TEST_DIRNAME/helpers/mock-api.sh" + +setup() { + export GITEA_TOKEN=test-token + export GIT_TAG_PREFIX="" + export SERVER_URL="http://localhost:18080" + export REPO="niko/test" + export SHA="abc123" + rm -rf /tmp/build-ctx +} + +teardown() { + mock_stop 2>/dev/null || true + rm -rf /tmp/build-ctx +} + +@test "VERSION_FILE=Chart.yaml extracts version from YAML" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/Chart.yaml" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "false" ] + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "VERSION_FILE=VERSION extracts version from plain text" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "false" ] + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "VERSION_FILE=package.json extracts version from JSON" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/package.json" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "false" ] + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "VERSION_FILE=subdir/Chart.yaml extracts version from monorepo" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/subdir/Chart.yaml" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "false" ] + [ "$NEXT_VERSION" = "0.4.0" ] +} + +@test "no VERSION_FILE, root VERSION found" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + WORKDIR=$(mktemp -d) + cp "$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" "$WORKDIR/VERSION" + + pushd "$WORKDIR" >/dev/null + run bash "$OLDPWD/scripts/check-version.sh" + popd >/dev/null + + rm -rf "$WORKDIR" + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "no VERSION_FILE, root Chart.yaml found" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + WORKDIR=$(mktemp -d) + cp "$BATS_TEST_DIRNAME/fixtures/check-version/Chart.yaml" "$WORKDIR/Chart.yaml" + + pushd "$WORKDIR" >/dev/null + run bash "$OLDPWD/scripts/check-version.sh" + popd >/dev/null + + rm -rf "$WORKDIR" + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "tag exists for commit sets ARTIFACT_EXISTS=true" { + mock_set_sequence '[{"code": 200, "body": [{"name": "0.3.0", "commit": {"sha": "abc123"}}]}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "true" ] + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "tag with prefix filters correctly" { + mock_set_sequence '[{"code": 200, "body": [{"name": "git-pages/0.3.0", "commit": {"sha": "abc123"}}, {"name": "docker/0.3.0", "commit": {"sha": "abc123"}}]}]' + mock_start + + export GIT_TAG_PREFIX="git-pages/" + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "true" ] + [ "$NEXT_VERSION" = "git-pages/0.3.0" ] +} + +@test "no tag, new version calculated" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "false" ] + [ "$NEXT_VERSION" = "0.3.0" ] +} + +@test "highest patch calculated correctly" { + mock_set_sequence '[{"code": 200, "body": [{"name": "0.3.0", "commit": {"sha": "def456"}}, {"name": "0.3.1", "commit": {"sha": "def456"}}]}]' + mock_start + + export VERSION_FILE="$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" + run bash scripts/check-version.sh + + [ "$status" -eq 0 ] + source /tmp/build-ctx/build.env + [ "$ARTIFACT_EXISTS" = "false" ] + [ "$NEXT_VERSION" = "0.3.2" ] +} + +@test "no version source exits with error" { + mock_set_sequence '[{"code": 200, "body": []}]' + mock_start + + WORKDIR=$(mktemp -d) + pushd "$WORKDIR" >/dev/null + run bash "$OLDPWD/scripts/check-version.sh" + popd >/dev/null + + rm -rf "$WORKDIR" + [ "$status" -eq 1 ] + [[ "$output" == *"ERROR"* ]] +} diff --git a/tests/fixtures/check-version/Chart.yaml b/tests/fixtures/check-version/Chart.yaml new file mode 100644 index 0000000..0f63843 --- /dev/null +++ b/tests/fixtures/check-version/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: test-chart +description: Test chart for version extraction +type: application +version: 0.3.0 +appVersion: "1.0.0" diff --git a/tests/fixtures/check-version/VERSION b/tests/fixtures/check-version/VERSION new file mode 100644 index 0000000..0d91a54 --- /dev/null +++ b/tests/fixtures/check-version/VERSION @@ -0,0 +1 @@ +0.3.0 diff --git a/tests/fixtures/check-version/package.json b/tests/fixtures/check-version/package.json new file mode 100644 index 0000000..edf216a --- /dev/null +++ b/tests/fixtures/check-version/package.json @@ -0,0 +1 @@ +{"version": "0.3.0"} diff --git a/tests/fixtures/check-version/pom.xml b/tests/fixtures/check-version/pom.xml new file mode 100644 index 0000000..2f69c2a --- /dev/null +++ b/tests/fixtures/check-version/pom.xml @@ -0,0 +1 @@ +0.3.0 diff --git a/tests/fixtures/check-version/subdir/Chart.yaml b/tests/fixtures/check-version/subdir/Chart.yaml new file mode 100644 index 0000000..744cae7 --- /dev/null +++ b/tests/fixtures/check-version/subdir/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: subdir-chart +description: Chart in subdirectory for monorepo testing +type: application +version: 0.4.0 +appVersion: "1.0.0" -- 2.52.0 From f07bdeb86d6051aa9c6aac7e8f7c9bc97453646f Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 08:05:36 +0300 Subject: [PATCH 07/10] testin korjaus --- tests/check-version.bats | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/check-version.bats b/tests/check-version.bats index 6618e94..a08d154 100644 --- a/tests/check-version.bats +++ b/tests/check-version.bats @@ -75,9 +75,10 @@ teardown() { WORKDIR=$(mktemp -d) cp "$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" "$WORKDIR/VERSION" - pushd "$WORKDIR" >/dev/null - run bash "$OLDPWD/scripts/check-version.sh" - popd >/dev/null + SCRIPT="$PWD/scripts/check-version.sh" + cd "$WORKDIR" + run bash "$SCRIPT" + cd - >/dev/null rm -rf "$WORKDIR" [ "$status" -eq 0 ] @@ -92,9 +93,10 @@ teardown() { WORKDIR=$(mktemp -d) cp "$BATS_TEST_DIRNAME/fixtures/check-version/Chart.yaml" "$WORKDIR/Chart.yaml" - pushd "$WORKDIR" >/dev/null - run bash "$OLDPWD/scripts/check-version.sh" - popd >/dev/null + SCRIPT="$PWD/scripts/check-version.sh" + cd "$WORKDIR" + run bash "$SCRIPT" + cd - >/dev/null rm -rf "$WORKDIR" [ "$status" -eq 0 ] @@ -160,9 +162,10 @@ teardown() { mock_start WORKDIR=$(mktemp -d) - pushd "$WORKDIR" >/dev/null - run bash "$OLDPWD/scripts/check-version.sh" - popd >/dev/null + SCRIPT="$PWD/scripts/check-version.sh" + cd "$WORKDIR" + run bash "$SCRIPT" + cd - >/dev/null rm -rf "$WORKDIR" [ "$status" -eq 1 ] -- 2.52.0 From a3225843d48de95bfaa88b1b7f492c1f78b3188b Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 08:17:28 +0300 Subject: [PATCH 08/10] test setup ci yhteensopivaksi --- tests/check-version.bats | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/check-version.bats b/tests/check-version.bats index a08d154..028e932 100644 --- a/tests/check-version.bats +++ b/tests/check-version.bats @@ -76,9 +76,7 @@ teardown() { cp "$BATS_TEST_DIRNAME/fixtures/check-version/VERSION" "$WORKDIR/VERSION" SCRIPT="$PWD/scripts/check-version.sh" - cd "$WORKDIR" - run bash "$SCRIPT" - cd - >/dev/null + run bash -c "cd '$WORKDIR' && exec bash '$SCRIPT'" rm -rf "$WORKDIR" [ "$status" -eq 0 ] @@ -94,9 +92,7 @@ teardown() { cp "$BATS_TEST_DIRNAME/fixtures/check-version/Chart.yaml" "$WORKDIR/Chart.yaml" SCRIPT="$PWD/scripts/check-version.sh" - cd "$WORKDIR" - run bash "$SCRIPT" - cd - >/dev/null + run bash -c "cd '$WORKDIR' && exec bash '$SCRIPT'" rm -rf "$WORKDIR" [ "$status" -eq 0 ] @@ -163,9 +159,7 @@ teardown() { WORKDIR=$(mktemp -d) SCRIPT="$PWD/scripts/check-version.sh" - cd "$WORKDIR" - run bash "$SCRIPT" - cd - >/dev/null + run bash -c "cd '$WORKDIR' && exec bash '$SCRIPT'" rm -rf "$WORKDIR" [ "$status" -eq 1 ] -- 2.52.0 From ede87654f4eacc0940d9c69bcfd2d4478bff72d3 Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 08:31:14 +0300 Subject: [PATCH 09/10] test korjaus --- scripts/check-version.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/check-version.sh b/scripts/check-version.sh index 6adcf77..0f588c0 100755 --- a/scripts/check-version.sh +++ b/scripts/check-version.sh @@ -3,7 +3,7 @@ set -e RAW_VERSION="" -if [ -n "${VERSION_FILE}" ] && [ -f "${VERSION_FILE}" ]; then +if [ -n "${VERSION_FILE-}" ] && [ -f "${VERSION_FILE-}" ]; then RAW_VERSION=$(sed -n 's/^version:[[:space:]]*\([^[:space:]]*\).*/\1/p' "${VERSION_FILE}") if [ -z "${RAW_VERSION}" ]; then if echo "${VERSION_FILE}" | grep -q -E '\.json$'; then @@ -35,7 +35,7 @@ echo "gitea-ci-library - Tunnistettu Major.Minor versio: $BASE_VERSION" TAGS_JSON=$(curl -s -f -H "Authorization: token ${GITEA_TOKEN}" \ "${SERVER_URL}/api/v1/repos/${REPO}/tags") -TAG=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX}" --arg sha "${SHA}" ' +TAG=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX-}" --arg sha "${SHA}" ' if type == "array" then .[] | select(.commit.sha == $sha and (.name | startswith($prefix))) | .name else empty end' | head -1) @@ -49,7 +49,7 @@ if [ -n "$TAG" ]; then else echo "ARTIFACT_EXISTS=false" > /tmp/build-ctx/build.env - HIGHEST_PATCH=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX}" --arg bv "${GIT_TAG_PREFIX}${BASE_VERSION}." ' + HIGHEST_PATCH=$(echo "$TAGS_JSON" | jq -r --arg prefix "${GIT_TAG_PREFIX-}" --arg bv "${GIT_TAG_PREFIX-}${BASE_VERSION}." ' if type == "array" then .[] | .name | select(startswith($bv)) | sub($bv; "") | tonumber else empty end' | sort -rn | head -1) if [ -z "$HIGHEST_PATCH" ]; then NEXT_PATCH=0; else NEXT_PATCH=$((HIGHEST_PATCH + 1)); fi -- 2.52.0 From 42c8ed9bd4202b5e80621fdc1670f3795ec81af6 Mon Sep 17 00:00:00 2001 From: moilanik Date: Fri, 19 Jun 2026 08:34:10 +0300 Subject: [PATCH 10/10] trigger helm build --- git-pages/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-pages/README.md b/git-pages/README.md index 9b47223..321b7ed 100644 --- a/git-pages/README.md +++ b/git-pages/README.md @@ -68,7 +68,7 @@ open "https://gitea.app.keskikuja.site/${REPO_OWNER}/${REPO_NAME}/settings/actio > 💡 **Monelle repoille:** Toista vaiheet 3–4, tai katso [automatisointi](docs/secrets.md#automatisointi-useamman-repon-salaisuuden-lis%C3%A4%C3%A4miseen). ---- +--- ## Käyttöönotto -- 2.52.0