Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c0012ba6fa |
@@ -27,54 +27,17 @@ jobs:
|
|||||||
version: ${{ steps.set-outputs.outputs.version }}
|
version: ${{ steps.set-outputs.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: niko/gitea-ci-library
|
||||||
|
path: .ci
|
||||||
|
|
||||||
- name: Check existing artifact and calculate version
|
- name: Check existing artifact and calculate version
|
||||||
run: |
|
env:
|
||||||
if [ -n "${VERSION_FILE}" ]; then
|
SERVER_URL: ${{ gitea.server_url }}
|
||||||
if echo "${VERSION_FILE}" | grep -q '\.json$'; then
|
REPO: ${{ github.repository }}
|
||||||
RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}")
|
SHA: ${{ github.sha }}
|
||||||
else
|
run: bash .ci/scripts/check-version.sh
|
||||||
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 '<version>\K[^<]+' pom.xml | head -1)
|
|
||||||
else
|
|
||||||
echo "ERROR: No VERSION file, package.json, 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
|
|
||||||
|
|
||||||
- name: Set job outputs
|
- name: Set job outputs
|
||||||
id: set-outputs
|
id: set-outputs
|
||||||
|
|||||||
@@ -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: ""
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
+25
-6
@@ -1,6 +1,6 @@
|
|||||||
# AI Context: Gitea Actions CI -kirjasto
|
# 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
|
## Project Overview
|
||||||
Gitea Actions reusable workflow -kirjasto mikropalveluiden build-, testaus-,
|
Gitea Actions reusable workflow -kirjasto mikropalveluiden build-, testaus-,
|
||||||
@@ -11,8 +11,8 @@ käyttävät kirjastoa `uses:`-direktiivillä.
|
|||||||
## Monorepo: kaksi erillistä kokonaisuutta
|
## Monorepo: kaksi erillistä kokonaisuutta
|
||||||
|
|
||||||
### 1. Juuri (`gitea-ci-library`)
|
### 1. Juuri (`gitea-ci-library`)
|
||||||
Provider-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio.
|
Provider- ja consumer-kirjasto: reusable workflowt, scriptit, ADRt, dokumentaatio,
|
||||||
Consumer kutsuu provider-workflowta `uses:`-direktiivillä.
|
ja consumer-esimerkit (dogfood). Consumer kutsuu provider-workflowta `uses:`-direktiivillä.
|
||||||
|
|
||||||
### 2. `git-pages/` — oma kokonaisuus
|
### 2. `git-pages/` — oma kokonaisuus
|
||||||
Helm-chartti Codeberg git-pagesille. Täysin itsenäinen — oma dokumentaatio,
|
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` |
|
| `scripts/` | Provider-skriptit: `report-status.sh`, `publish-git-pages.sh`, `ci-validate.sh` |
|
||||||
| `.gitea/scripts/` | **Consumer-skriptit**: `bats-coverage.sh`, `bats-report.sh` |
|
| `.gitea/scripts/` | **Consumer-skriptit**: `bats-coverage.sh`, `bats-report.sh` |
|
||||||
| `docs/` | Arkkitehtuuri, ADRt (0004–0008) |
|
| `docs/` | Arkkitehtuuri, ADRt (0004–0008) |
|
||||||
| `skills/consumer-pipelines/` | Consumer-pipeline-standardit — AI:n pakottavat säännöt consumer-CI:lle |
|
| `skills/consumer-pipelines/` | Consumer-pipeline-standardit (ks. Project Skills). Koskee vain consumer-puolta |
|
||||||
| `skills/ci-container-build/` | CI-kontin build-workflow'n template — `ci-container-build-push.yml` |
|
| `skills/ci-container-build/` | CI-kontin build-workflow'n template (ks. Project Skills) |
|
||||||
| `docs/adr/` | Architecture Decision Records |
|
| `docs/adr/` | Architecture Decision Records |
|
||||||
| `git-pages/` | Raporttien hostaus (Helm-chartti) |
|
| `git-pages/` | Raporttien hostaus (Helm-chartti) |
|
||||||
| `tests/` | Bats-testit skripteille |
|
| `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-cucumber-tests.yml` | workflow_call | Hyväksymätestit Cucumberilla, raportit git-pagesiin, status linkillä |
|
||||||
| `example-gitea-env.conf` | — | KEY=VALUE config tälle repolle |
|
| `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
|
## 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
|
- **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.
|
- **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.
|
- **Exit-koodi on ainoa onnistumisen mittari**: Ei pipeä, ei tiedostoheuristiikkaa. ADR 0008.
|
||||||
|
|||||||
+1
-1
@@ -38,4 +38,4 @@ suoraan Gitea UI:ssa.
|
|||||||
| **Multi-Git-platform** | Vain Gitea — yksi alusta kunnolla (periaate 10) |
|
| **Multi-Git-platform** | Vain Gitea — yksi alusta kunnolla (periaate 10) |
|
||||||
| **Custom actionit** | Reusable workflow on kevyempi ja natiivimpi (periaate 2) |
|
| **Custom actionit** | Reusable workflow on kevyempi ja natiivimpi (periaate 2) |
|
||||||
| **Ulkoinen orkestraattori** | Gitean `needs` + `if` hoitaa ohjauksen |
|
| **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 |
|
||||||
|
|||||||
@@ -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}/<chart-name>:${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}/<chart-name>:${VERSION}`**
|
||||||
|
Esim. `oci://gitea.app.keskikuja.site/niko/git-pages:1.2.3`
|
||||||
|
|
||||||
|
Chartin nimi (`<chart-name>`) 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
|
||||||
Executable
+60
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RAW_VERSION=""
|
||||||
|
|
||||||
|
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
|
||||||
|
RAW_VERSION=$(jq -r '.version' "${VERSION_FILE}")
|
||||||
|
else
|
||||||
|
RAW_VERSION=$(cat "${VERSION_FILE}" | tr -d '[:space:]')
|
||||||
|
fi
|
||||||
|
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 '<version>\K[^<]+' pom.xml | head -1)
|
||||||
|
elif [ -f Chart.yaml ]; then
|
||||||
|
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
|
||||||
|
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
|
||||||
@@ -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: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
<test-1>:
|
||||||
|
needs: [load-config]
|
||||||
|
uses: ./.gitea/workflows/<component>.<test-1>.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
|
|
||||||
|
<test-2>:
|
||||||
|
needs: [load-config]
|
||||||
|
uses: ./.gitea/workflows/<component>.<test-2>.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
|
|
||||||
|
report-summary:
|
||||||
|
needs: [load-config, <test-1>, <test-2>]
|
||||||
|
if: always()
|
||||||
|
uses: <owner>/gitea-ci-library/.gitea/workflows/report-summary.yml@v1
|
||||||
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
|
suites: <suite-1> <suite-2>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 <työkalu>
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
config_path:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: '.gitea/workflows/<komponentti>.gitea-env.conf'
|
||||||
|
description: 'Polku .gitea-env.conf-tiedostoon'
|
||||||
|
dockerfile_path:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: '<komponentti>/Dockerfile.ci-<työkalu>'
|
||||||
|
description: 'Polku Dockerfileen'
|
||||||
|
image_name:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'ci-<työkalu>'
|
||||||
|
description: 'Kontin nimi ilman registry-polkua'
|
||||||
|
tag:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
default: 'latest'
|
||||||
|
description: 'Image-tägi'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
load-config:
|
||||||
|
uses: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
config_path: ${{ inputs.config_path }}
|
||||||
|
|
||||||
|
build-push:
|
||||||
|
needs: [load-config]
|
||||||
|
uses: <owner>/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:
|
||||||
|
<työkalu>:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ inputs.<image-name> }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: <owner>/gitea-ci-library
|
||||||
|
path: .ci
|
||||||
|
|
||||||
|
- name: Run <työkalu>
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p "reports/<suite>"
|
||||||
|
<komento> > "reports/<suite>/results.txt" 2>&1
|
||||||
|
|
||||||
|
- name: Post-process reports
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
<mahdollinen_raporttien_jälkikäsittely>
|
||||||
|
|
||||||
|
- name: Report
|
||||||
|
if: always()
|
||||||
|
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> ${{ 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 <image>` 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/<suite>"
|
||||||
|
<testikomento>
|
||||||
|
|
||||||
|
- name: Report
|
||||||
|
if: always()
|
||||||
|
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> ${{ job.status }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Taso 2: Jälkikäsittely tarvitaan
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Run tests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p "reports/<suite>"
|
||||||
|
<testikomento> > "reports/<suite>/results.txt" 2>&1
|
||||||
|
|
||||||
|
- name: Post-process coverage
|
||||||
|
if: always()
|
||||||
|
run: <siirrä coverage-data reports/<suite>/coverage/-hakemistoon>
|
||||||
|
|
||||||
|
- name: Post-process test report
|
||||||
|
if: always()
|
||||||
|
run: <HTML-generointi raa'asta outputista>
|
||||||
|
|
||||||
|
- name: Report
|
||||||
|
if: always()
|
||||||
|
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> ${{ 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/<suite>/`-hakemistoa.
|
||||||
|
|
||||||
|
### Mitä skannataan
|
||||||
|
|
||||||
|
| Mitä | Sääntö |
|
||||||
|
|---|---|
|
||||||
|
| **Tiedostot (FILES)** | Kaikki `reports/<suite>/`-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/<suite>/index.html`-sivun, linkit kaikkiin itemeihin |
|
||||||
|
|
||||||
|
### Hakemistorakenne
|
||||||
|
|
||||||
|
```
|
||||||
|
reports/<suite>/
|
||||||
|
├── results.txt ← testin stdout (skannataan FILES)
|
||||||
|
├── test-report.html ← generoitu HTML (skannataan FILES)
|
||||||
|
└── <mikä tahansa>/ ← alihakemisto (skannataan SUBDIRS)
|
||||||
|
└── index.html ← VAIN jos tämä on olemassa
|
||||||
|
```
|
||||||
|
|
||||||
|
### Esimerkki: coverage-näkymä
|
||||||
|
|
||||||
|
```
|
||||||
|
reports/<suite>/coverage/index.html ← on olemassa
|
||||||
|
```
|
||||||
|
|
||||||
|
Coverage-dataa ei siirretä automaattisesti. Testin tai post-process-stepin pitää
|
||||||
|
siirtää coverage `reports/<suite>/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/<suite>/`-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/<komponentti>.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: ['<komponentti>/**'] }` |
|
||||||
|
| Jokaisella komponentilla oma versio | `VERSION_FILE=<komponentti>/package.json` confissa |
|
||||||
|
| Git-tägit sekaisin ellei nimiavaruutta | `GIT_TAG_PREFIX=<komponentti>/` confissa → tägi `<komponentti>/1.2.3` |
|
||||||
|
| Eri julkaisutahdit | Riippumattomat CI-triggerit, omat versiopolut |
|
||||||
|
|
||||||
|
### Komponenttikohtainen conf
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# .gitea/workflows/<komponentti>.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=<image-nimi>
|
||||||
|
DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container
|
||||||
|
GIT_TAG_PREFIX=<komponentti>/
|
||||||
|
# Jompikumpi — JSON (.version-kenttä) tai plain text:
|
||||||
|
VERSION_FILE=<komponentti>/package.json
|
||||||
|
#VERSION_FILE=<komponentti>/VERSION
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monorepo reititin
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: CI <Komponentti> Main
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- '<komponentti>/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
load-config:
|
||||||
|
uses: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
config_path: .gitea/workflows/<komponentti>.gitea-env.conf
|
||||||
|
|
||||||
|
check-version:
|
||||||
|
needs: [load-config]
|
||||||
|
uses: <owner>/gitea-ci-library/.gitea/workflows/check-version.yml@v1
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
|
|
||||||
|
<testit>:
|
||||||
|
needs: [load-config, check-version]
|
||||||
|
if: needs.check-version.outputs.artifact_exists != 'true'
|
||||||
|
uses: ./.gitea/workflows/<komponentti>.<testi>.yml
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
|
|
||||||
|
build-push:
|
||||||
|
needs: [load-config, check-version, <testit>]
|
||||||
|
if: needs.check-version.outputs.artifact_exists != 'true'
|
||||||
|
uses: <owner>/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: <owner>/gitea-ci-library/.gitea/workflows/report-summary.yml@v1
|
||||||
|
with:
|
||||||
|
env_json: ${{ needs.load-config.outputs.env_json }}
|
||||||
|
suites: '<suite-1> <suite-2>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Version elinkaari per komponentti
|
||||||
|
|
||||||
|
`GIT_TAG_PREFIX` takaa että eri komponenttien versiohistoria pysyy erillään.
|
||||||
|
Git-tägi `<komponentti>/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) | `<version>`-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 "<kuvaus>" <context> <suite> ${{ 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ä) |
|
||||||
@@ -19,6 +19,8 @@ impact: high
|
|||||||
Säännöt joilla consumer-projektit rakentavat CI-pipelinejä `gitea-ci-library`-kirjaston päälle.
|
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.
|
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
|
## 1. Reitittimen puhtaus
|
||||||
|
|
||||||
Reitittimet (`ci-feature.yml`, `ci-main.yml`) eivät sisällä `run:`-steppejä. Ne koostuvat vain:
|
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
|
Jokainen job vastaa yhtä loogista testiä tai operaatiota. Reititin on orkestraattori — kaikki suorittava
|
||||||
logiikka on omassa `workflow_call`-tiedostossaan.
|
logiikka on omassa `workflow_call`-tiedostossaan.
|
||||||
|
|
||||||
**Esimerkki:**
|
Katso täydellinen esimerkki `REFERENCE.md`:stä.
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
load-config:
|
|
||||||
uses: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
<test-1>:
|
|
||||||
needs: [load-config]
|
|
||||||
uses: ./.gitea/workflows/<component>.<test-1>.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
|
||||||
|
|
||||||
<test-2>:
|
|
||||||
needs: [load-config]
|
|
||||||
uses: ./.gitea/workflows/<component>.<test-2>.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
|
||||||
|
|
||||||
report-summary:
|
|
||||||
needs: [load-config, <test-1>, <test-2>]
|
|
||||||
if: always()
|
|
||||||
uses: <owner>/gitea-ci-library/.gitea/workflows/report-summary.yml@v1
|
|
||||||
with:
|
|
||||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
|
||||||
suites: <suite-1> <suite-2>
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. Yksi asia per tiedosto
|
## 2. Yksi asia per tiedosto
|
||||||
|
|
||||||
@@ -89,310 +62,60 @@ ja exit-koodi välittyy natiivisti. Ylimääräistä `EXIT=$?` + `echo >> GITHUB
|
|||||||
<testikomento> > results.txt 2>&1
|
<testikomento> > results.txt 2>&1
|
||||||
```
|
```
|
||||||
|
|
||||||
**Miksi ei pipeä (`| tee`):**
|
**Miksi ei pipeä (`| tee`):** `|` syö exit-koodin. Käytä redirectiä `>`.
|
||||||
|
|
||||||
```bash
|
**Yksi asia per step:** Älä koskaan niputa useaa komentoa samaan `run:`-blockiin. `bash -e` pysäyttää
|
||||||
# VÄÄRIN — pipe syö exit-koodin
|
koko stepin ensimmäisellä failaavalla komennolla, ja loput jäävät ajamatta. Sama pätee post-process-steppeihin.
|
||||||
<komento> | tee results.txt
|
|
||||||
|
|
||||||
# OIKEIN — redirect tiedostoon
|
|
||||||
<komento> > 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. Konttipolitiikka
|
## 4. Konttipolitiikka
|
||||||
|
|
||||||
1. **Julkiset registry-kontit kiinteällä versiolla** — `alpine/helm:3.19.0`, `node:22`, `maven:3.9-eclipse-temurin-21`.
|
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-<kontti>.yml`:llä.
|
2. **Projektin omat CI-kontit `latest`-tägillä** — buildattu `ci-container-build-<kontti>.yml`:llä.
|
||||||
Kontin build-pipeline päivittää `latest`:n automaattisesti. Rebuild = käyttöönotto
|
Kontin build-pipeline päivittää `latest`:n automaattisesti. Rebuild = käyttöönotto
|
||||||
kaikissa pipelineissa ilman versioviittauksien päivittelyä.
|
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,
|
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
|
4. **Konttikuva hallitaan workflow'ssa, ei kutsujassa** — jos workflow vaatii tietyn
|
||||||
konttikuvan, se määritellään oletuksena (`default:`) workflow'n inputissa.
|
konttikuvan, se määritellään oletuksena (`default:`) workflow'n inputissa.
|
||||||
Kutsujan ei tarvitse tietää eikä välittää image-nimeä ellei halua ylikirjoittaa.
|
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ää
|
CI-kontin build-workflow'n template: `skills/ci-container-build/SKILL.md`.
|
||||||
valmiin `ci-container-build-<kontti>.yml`-pohjan jossa `workflow_dispatch`-tuki manuaaliajoon.
|
|
||||||
|
|
||||||
### 4.1 CI-kontin ajaminen jobissa
|
### 4.1 CI-kontin ajaminen jobissa
|
||||||
|
|
||||||
Ainoa sallittu tapa on `container:`-direktiivi. `docker run` komennolla kontin
|
Ainoa sallittu tapa on `container:`-direktiivi. `docker run` komennolla kontin
|
||||||
käynnistäminen stepin sisällä on anti-pattern.
|
käynnistäminen stepin sisällä on anti-pattern.
|
||||||
|
|
||||||
**Miksi:** `docker run` erilliskonttina aiheuttaa:
|
Katso CI-kontin template `REFERENCE.md`:stä.
|
||||||
- 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:
|
|
||||||
<työkalu>:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: ${{ inputs.<image-name> }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: <owner>/gitea-ci-library
|
|
||||||
path: .ci
|
|
||||||
|
|
||||||
- name: Run <työkalu>
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p "reports/<suite>"
|
|
||||||
<komento> > "reports/<suite>/results.txt" 2>&1
|
|
||||||
|
|
||||||
- name: Post-process reports
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
<mahdollinen_raporttien_jälkikäsittely>
|
|
||||||
|
|
||||||
- name: Report
|
|
||||||
if: always()
|
|
||||||
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> ${{ job.status }}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Huomio `actions/checkout@v4`:stä:** `container:`-direktiivillä kaikki stepit
|
**Huomio `actions/checkout@v4`:stä:** `container:`-direktiivillä kaikki stepit
|
||||||
ajetaan kontin *sisällä* — myös `actions/checkout@v4`. Se on JavaScript-action
|
ajetaan kontin *sisällä* — myös `actions/checkout@v4`. Se on JavaScript-action
|
||||||
joka vaatii sekä `nodejs` että `git`. Ilman kumpaa tahansa checkout feilaa
|
joka vaatii sekä `nodejs` että `git`. Varmista että CI-kontin Dockerfilessä on molemmat.
|
||||||
`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 <image>` 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
|
|
||||||
|
|
||||||
## 5. Raporttitasot
|
## 5. Raporttitasot
|
||||||
|
|
||||||
Testi tuottaa raportin `reports/<suite>/`-hakemistoon. Yksi `ci-report.sh`-kutsu hoitaa sekä
|
Testi tuottaa raportin `reports/<suite>/`-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ä
|
### Taso 1: Ei jälkikäsittelyä
|
||||||
|
|
||||||
Kun testi tuottaa raportit suoraan (kuten `pytest --html` tai `cucumber-js --format html`):
|
Kun testi tuottaa raportit suoraan (kuten `pytest --html` tai `cucumber-js --format html`):
|
||||||
|
- testi kirjoittaa `reports/<suite>/`-hakemistoon
|
||||||
```yaml
|
- `ci-report.sh` julkaisee ja asettaa commit-statuksen
|
||||||
- name: Run tests
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p "reports/<suite>"
|
|
||||||
<testikomento>
|
|
||||||
|
|
||||||
- name: Report
|
|
||||||
if: always()
|
|
||||||
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> ${{ job.status }}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Taso 2: Jälkikäsittely tarvitaan
|
### Taso 2: Jälkikäsittely tarvitaan
|
||||||
|
|
||||||
Kun testi tuottaa raakadataa (stdout, coverage-tiedostot) joka pitää muuntaa tai siirtää
|
Kun testi tuottaa raakadataa (stdout, coverage-tiedostot) joka pitää muuntaa tai siirtää
|
||||||
`reports/<suite>/`-hakemistoon, käytetään Post-process-steppejä. **Jokainen operaatio
|
`reports/<suite>/`-hakemistoon. **Jokainen operaatio omassa stepissään** `if: always()`.
|
||||||
omassa stepissään** — älä koskaan niputa useaa post-process-komentoa samaan `run:`-blockiin:
|
|
||||||
|
|
||||||
```yaml
|
Tarkat YAML-mallit molemmista tasoista: `REFERENCE.md`.
|
||||||
- name: Run tests
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
mkdir -p "reports/<suite>"
|
|
||||||
<testikomento> > "reports/<suite>/results.txt" 2>&1
|
|
||||||
|
|
||||||
- name: Post-process coverage
|
|
||||||
if: always()
|
|
||||||
run: <siirrä coverage-data reports/<suite>/coverage/-hakemistoon>
|
|
||||||
|
|
||||||
- name: Post-process test report
|
|
||||||
if: always()
|
|
||||||
run: <HTML-generointi raa'asta outputista>
|
|
||||||
|
|
||||||
- name: Report
|
|
||||||
if: always()
|
|
||||||
run: bash .ci/scripts/ci-report.sh "<kuvaus>" <context> <suite> ${{ job.status }}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Huomio subdir-sisällöstä:** Jos testi tuottaa dataa alihakemistoon (esim.
|
|
||||||
coverage `./coverage/`-kansioon), se pitää erikseen SIIRTÄÄ
|
|
||||||
`reports/<suite>/<subdir>/`-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/<suite>/`-hakemistossa on useita tiedostoja tai alihakemistoja,
|
|
||||||
`ci-report.sh` generoi automaattisesti `reports/<suite>/index.html` jos hakemistossa
|
|
||||||
on enemmän kuin yksi raportoitava item.
|
|
||||||
|
|
||||||
```
|
|
||||||
reports/<suite>/
|
|
||||||
├── results.txt ← testin stdout (skannataan FILES)
|
|
||||||
├── test-report.html ← generoitu HTML (skannataan FILES)
|
|
||||||
└── <mikä tahansa>/ ← alihakemisto (skannataan SUBDIRS)
|
|
||||||
└── index.html ← VAIN jos tämä on olemassa
|
|
||||||
```
|
|
||||||
|
|
||||||
**Subdir-sääntö:** Alihakemisto näkyy indexissä VAIN jos se sisältää `index.html`:n.
|
**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
|
Tiedostonimet `.gitea/workflows/`-kansiossa noudattavat yhtenäistä rakennetta:
|
||||||
`reports/<suite>/`-hakemistoa.
|
|
||||||
|
|
||||||
### Mitä skannataan
|
|
||||||
|
|
||||||
| Mitä | Sääntö |
|
|
||||||
|---|---|
|
|
||||||
| **Tiedostot (FILES)** | Kaikki `reports/<suite>/`-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/<suite>/index.html`-sivun, linkit kaikkiin itemeihin |
|
|
||||||
|
|
||||||
### Esimerkki: coverage-näkymä
|
|
||||||
|
|
||||||
```
|
|
||||||
reports/<suite>/coverage/index.html ← on olemassa
|
|
||||||
```
|
|
||||||
|
|
||||||
Coverage-dataa ei siirretä automaattisesti. Testin tai post-process-stepin pitää
|
|
||||||
siirtää coverage `reports/<suite>/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ä:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
<komponentti>.ci-feature.yml ← feature-haaran reititin
|
<komponentti>.ci-feature.yml ← feature-haaran reititin
|
||||||
@@ -402,216 +125,35 @@ tiedostot löytyvät nopeasti ja niiden rooli on selvillä:
|
|||||||
<komponentti>.gitea-env.conf ← komponenttikohtainen konfiguraatio
|
<komponentti>.gitea-env.conf ← komponenttikohtainen konfiguraatio
|
||||||
```
|
```
|
||||||
|
|
||||||
Single repossa `<komponentti>` jätetään pois — tiedostot ovat suoraan `ci-feature.yml`,
|
Single repossa `<komponentti>` jätetään pois.
|
||||||
`ci-main.yml`, `<testityyppi>.yml`, `ci-container-build-<kontti>.yml`.
|
Monorepossa prefiksi pitää komponentin tiedostot yhdessä.
|
||||||
|
|
||||||
Monorepossa prefiksi pitää komponentin tiedostot yhdessä: `ls <komponentti>.*` löytää kaikki
|
## 7. Artifact-kuri
|
||||||
kerralla.
|
|
||||||
|
|
||||||
## 9. Artifact-kuri
|
|
||||||
|
|
||||||
Gitea Actionsin `upload-artifact` jättää pysyvän tiedoston. Artifakteja ei käytetä
|
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
|
**Ensisijainen ratkaisu:** jokainen testi tuottaa tarvitsemansa datan itse. Ei
|
||||||
`upload-artifact` + `download-artifact` -riippuvuuksia.
|
`upload-artifact` + `download-artifact` -riippuvuuksia.
|
||||||
|
|
||||||
```yaml
|
## 8. Report-Summary — pakollinen jokaisen pipelinen lopuksi
|
||||||
# OIKEIN — molemmat testit tuottavat oman datansa
|
|
||||||
- name: Prepare data
|
|
||||||
run: <komento> > /tmp/data
|
|
||||||
- name: Validate data
|
|
||||||
run: <validointikomento> /tmp/data
|
|
||||||
```
|
|
||||||
|
|
||||||
**Miksi:**
|
Jokaisen reitittimen (oli se `ci-main.yml`, `ci-feature.yml` tai mikä tahansa) viimeinen job on `report-summary`.
|
||||||
- Testit pysyvät itsenäisinä — yhden testin fail ei estä muita
|
|
||||||
- Ei "artifact expired" -virheitä myöhemmin
|
|
||||||
- Ei pysyviä artifakteja siivoamatta
|
|
||||||
|
|
||||||
---
|
**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
|
## 9. ADR-yhteenveto — consumerin kannalta oleelliset säännöt
|
||||||
|
|
||||||
```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/<komponentti>.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: ['<komponentti>/**'] }` |
|
|
||||||
| Jokaisella komponentilla oma versio | `VERSION_FILE=<komponentti>/package.json` confissa |
|
|
||||||
| Git-tägit sekaisin ellei nimiavaruutta | `GIT_TAG_PREFIX=<komponentti>/` confissa → tägi `<komponentti>/1.2.3` |
|
|
||||||
| Eri julkaisutahdit | Riippumattomat CI-triggerit, omat versiopolut |
|
|
||||||
|
|
||||||
### Komponenttikohtainen conf
|
|
||||||
|
|
||||||
```ini
|
|
||||||
# .gitea/workflows/<komponentti>.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=<image-nimi>
|
|
||||||
DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container
|
|
||||||
GIT_TAG_PREFIX=<komponentti>/
|
|
||||||
# Jompikumpi — JSON (.version-kenttä) tai plain text:
|
|
||||||
VERSION_FILE=<komponentti>/package.json
|
|
||||||
#VERSION_FILE=<komponentti>/VERSION
|
|
||||||
```
|
|
||||||
|
|
||||||
### Monorepo reititin
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
name: CI <Komponentti> Main
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
paths:
|
|
||||||
- '<komponentti>/**'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
load-config:
|
|
||||||
uses: <owner>/gitea-ci-library/.gitea/workflows/config-provider.yml@v1
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
config_path: .gitea/workflows/<komponentti>.gitea-env.conf
|
|
||||||
|
|
||||||
check-version:
|
|
||||||
needs: [load-config]
|
|
||||||
uses: <owner>/gitea-ci-library/.gitea/workflows/check-version.yml@v1
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
|
||||||
|
|
||||||
<testit>:
|
|
||||||
needs: [load-config, check-version]
|
|
||||||
if: needs.check-version.outputs.artifact_exists != 'true'
|
|
||||||
uses: ./.gitea/workflows/<komponentti>.<testi>.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
env_json: ${{ needs.load-config.outputs.env_json }}
|
|
||||||
|
|
||||||
build-push:
|
|
||||||
needs: [load-config, check-version, <testit>]
|
|
||||||
if: needs.check-version.outputs.artifact_exists != 'true'
|
|
||||||
uses: <owner>/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 `<komponentti>/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) | `<version>`-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 "<kuvaus>" <context> <suite> ${{ 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
|
|
||||||
|
|
||||||
### Reititin ei sisällä suorittavaa koodia (ADR 0010)
|
### 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ä
|
### Paikalliset `uses:` eivät käytä refiä
|
||||||
|
|
||||||
Gitea act runner v1.0.8 muodostaa paikallisista `uses: ./.gitea/workflows/*.yml@main`-viittauksista
|
Gitea act runner v1.0.8 muodostaa paikallisista `uses: ./.gitea/workflows/*.yml@main`-viittauksista
|
||||||
epävalidin git-refin `main@<sha>`, joka aiheuttaa virheen `Revision invalid : reference must
|
epävalidin git-refin `main@<sha>`.
|
||||||
be defined once at the beginning`.
|
|
||||||
|
|
||||||
Paikallisista `uses:`-direktiiveistä EI koskaan käytetä `@main`- tai muuta ref-päätettä:
|
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` ← oikein
|
||||||
- `uses: ./.gitea/workflows/chart.helm-lint.yml@main` ← väärin
|
- `uses: ./.gitea/workflows/chart.helm-lint.yml@main` ← väärin
|
||||||
|
|
||||||
Ilman refiä runner käyttää workflow'ta triggeröivästä commitista. Ulkoisten repojen
|
Ilman refiä runner käyttää workflow'ta triggeröivästä commitista.
|
||||||
viittauksissa (`niko/...@v1`) pääte pysyy. Nämä resolvoidaan eri reittiä ja toimivat oikein.
|
|
||||||
|
|
||||||
### Exit-koodi on ainoa onnistumisen mittari (ADR 0008)
|
### Exit-koodi on ainoa onnistumisen mittari (ADR 0008)
|
||||||
|
|
||||||
Ei pipeä (`|`) komennon perässä — se syö exit-koodin. Käytä redirectiä (`> file 2>&1`).
|
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 checkout ei kuulu consumerille
|
||||||
|
|
||||||
Providerin scriptit haetaan `actions/checkout`-stepillä `.ci/`-polkuun.
|
Providerin scriptit haetaan `actions/checkout`-stepillä `.ci/`-polkuun.
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#!/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"
|
||||||
|
|
||||||
|
SCRIPT="$PWD/scripts/check-version.sh"
|
||||||
|
run bash -c "cd '$WORKDIR' && exec bash '$SCRIPT'"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
SCRIPT="$PWD/scripts/check-version.sh"
|
||||||
|
run bash -c "cd '$WORKDIR' && exec bash '$SCRIPT'"
|
||||||
|
|
||||||
|
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)
|
||||||
|
SCRIPT="$PWD/scripts/check-version.sh"
|
||||||
|
run bash -c "cd '$WORKDIR' && exec bash '$SCRIPT'"
|
||||||
|
|
||||||
|
rm -rf "$WORKDIR"
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
[[ "$output" == *"ERROR"* ]]
|
||||||
|
}
|
||||||
+6
@@ -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"
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
0.3.0
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
{"version": "0.3.0"}
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
<project><version>0.3.0</version></project>
|
||||||
@@ -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"
|
||||||
Reference in New Issue
Block a user