consumer project käyttöönotossa tulleitea muutoksia (#12)
CI Main / Load example-gitea-env.conf to pipeline env (push) Successful in 18s
CI Main / Check existing artifact (push) Successful in 12s
unit-tests Link to Bats reports
CI Main / Bats tests (push) Successful in 1m41s
acc-tests Link to Cucumber reports
CI Main / Cucumber tests (push) Successful in 1m7s
ci-docker-build-push Docker build & push 0.2.1 OK
CI Main / Build & Push Docker (push) Successful in 34s
CI Main / Report Summary (push) Successful in 4s
CI Main / Load example-gitea-env.conf to pipeline env (push) Successful in 18s
CI Main / Check existing artifact (push) Successful in 12s
unit-tests Link to Bats reports
CI Main / Bats tests (push) Successful in 1m41s
acc-tests Link to Cucumber reports
CI Main / Cucumber tests (push) Successful in 1m7s
ci-docker-build-push Docker build & push 0.2.1 OK
CI Main / Build & Push Docker (push) Successful in 34s
CI Main / Report Summary (push) Successful in 4s
Co-authored-by: moilanik <niko.moilanen@tietoevry.com> Reviewed-on: #12
This commit was merged in pull request #12.
This commit is contained in:
+109
-254
@@ -1,269 +1,124 @@
|
||||
# Konfiguraatiomalli — `ci-flow-values.yaml`
|
||||
# Konfiguraatiomalli — `gitea-env.conf`
|
||||
|
||||
> ⚠️ **POC-vaihe.** Tämä dokumentti on peritty Jenkins-versiosta ja sisältää
|
||||
> Docker-spesifistä legacyä (isContainerBuild, Docker-labelit). POC osoitti,
|
||||
> että provider on agnostinen consumerin build-ekosysteemille.
|
||||
>
|
||||
> Uusi ajattelu: `isContainerBuild()` → `isArtifactBuild()`. Provider ei
|
||||
> tiedä eikä tarvitse tietää, buildaako consumer kontin, JARin, npm-paketin
|
||||
> vai mitään muuta. Dokumentti odottaa uudelleenkirjoitusta.
|
||||
>
|
||||
> Normatiivinen lähde: `docs/design-rationale.md`, ADR 0005.
|
||||
> Consumer määrittelee ympäristökohtaiset arvot KEY=VALUE-muotoisessa
|
||||
> `.conf`-tiedostossa. Providerin `config-provider.yml` validoi tiedoston
|
||||
> ja muuntaa sen JSON:ksi (`env_json`), jota kaikki downstream-workflowt
|
||||
> käyttävät.
|
||||
|
||||
---
|
||||
|
||||
## Miksi redesign
|
||||
## Tiedoston sijainti ja nimi
|
||||
|
||||
Jenkins-version `ci-flow-values.yaml` oli rakennettu Jenkinsin ympäristömuuttuja- ja credential-mallin ympärille. Gitea Actionsissa konfiguraatio luetaan suoraan YAML:sta workflow'n sisällä — ei tarvita env-muuttujien kautta kierrättämistä. Lisäksi:
|
||||
Consumerin repossa: `.gitea/workflows/gitea-env.conf` (nimi vapaasti
|
||||
valittavissa — `config-provider.yml`:n `config_path`-input määrittää polun).
|
||||
|
||||
- `creditentials`-viittaukset korvautuvat Gitea org secrets/variables -mekanismilla
|
||||
- `test-flow`-syntaksi yksinkertaistuu (ei enää JSON-serialisointia env-muuttujiin)
|
||||
- Docker/NPM-rekisterit MVP:ssä vain Gitea Packages — factory/adapter-pattern valmiina laajennukselle
|
||||
- `sonarqube`-konfiguraatio pysyy samankaltaisena
|
||||
|
||||
---
|
||||
Esimerkki (tämän repon dogfood):
|
||||
```
|
||||
.gitea/workflows/example-gitea-env.conf
|
||||
```
|
||||
|
||||
## Skeema
|
||||
|
||||
```
|
||||
KEY=VALUE
|
||||
```
|
||||
|
||||
Yksi `KEY=VALUE` per rivi. Kommentit `#`-merkillä. Tyhjät rivit ohitetaan.
|
||||
|
||||
### Pakolliset avaimet
|
||||
|
||||
| Avain | Kuvaus | Esimerkki |
|
||||
|---|---|---|
|
||||
| `GITEA_API_URL` | Gitea-instanssin URL | `https://gitea.example.com` |
|
||||
| `GIT_PAGES_URL` | Raporttihostauksen URL | `https://reports.example.com` |
|
||||
|
||||
### Docker-spesifit avaimet (vain jos käytetään `docker-build-push.yml`)
|
||||
|
||||
| Avain | Pakollinen | Kuvaus |
|
||||
|---|---|---|
|
||||
| `DOCKER_REGISTRY` | Kyllä | Rekisterin host/path, esim. `gitea.example.com/org` |
|
||||
| `DOCKER_IMAGE_NAME` | Kyllä | Kontin nimi ilman registry-prefixiä |
|
||||
| `DOCKER_UI_URL` | Ei | Linkki kontin UI-näkymään registryssä |
|
||||
| `DOCKERFILE` | Ei | Dockerfile-nimi, oletus `Dockerfile` |
|
||||
|
||||
### Esimerkki
|
||||
|
||||
```ini
|
||||
GITEA_API_URL=https://gitea.example.com
|
||||
GIT_PAGES_URL=https://reports.example.com
|
||||
DOCKER_REGISTRY=gitea.example.com/myorg
|
||||
DOCKER_IMAGE_NAME=temperature-store
|
||||
DOCKER_UI_URL=https://gitea.example.com/myorg/-/packages/container/temperature-store
|
||||
#DOCKERFILE=Dockerfile.platform
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Salaisuudet
|
||||
|
||||
Salaisuudet eivät ole `.conf`-tiedostossa. Ne määritellään Gitean
|
||||
organization/repository secrets -mekanismissa ja välitetään workflowlle
|
||||
`secrets: inherit` -direktiivillä.
|
||||
|
||||
| Secret | Pakollinen | Käyttäjä |
|
||||
|---|---|---|
|
||||
| `GITEA_TOKEN` | Kyllä | `report-status.sh`, `check-version.yml`, `docker-build-push.yml` |
|
||||
| `GIT_PAGES_PUBLISH_TOKEN` | Kyllä | `publish-git-pages.sh`, `config-provider.yml` (validointi) |
|
||||
| `DOCKER_USERNAME` | Ei | `docker-build-push.yml` (oletus: `github.actor`, ei pakollinen kaikissa registryissä) |
|
||||
| `DOCKER_PASSWORD` | Kyllä | `docker-build-push.yml` |
|
||||
|
||||
---
|
||||
|
||||
## `config-provider.yml` — lataus ja validointi
|
||||
|
||||
Provider-workflow joka lukee `.conf`-tiedoston, validoi sen ja palauttaa
|
||||
JSON-muotoisen `env_json`:n.
|
||||
|
||||
**Input:** `config_path` (polku `.conf`-tiedostoon)
|
||||
|
||||
**Output:** `env_json` (JSON-string), `config_path` (sama polku takaisin)
|
||||
|
||||
**Validointi:**
|
||||
- `.conf`-tiedosto on olemassa
|
||||
- Jokaisella `KEY=VALUE`-rivillä on arvo (ei tyhjää)
|
||||
- URL-tyyppiset avaimet alkavat `http://` tai `https://`
|
||||
- Pakolliset secretit (`GITEA_TOKEN`, `GIT_PAGES_PUBLISH_TOKEN`) on asetettu
|
||||
|
||||
Kutsu:
|
||||
```yaml
|
||||
# ci-flow-values.yaml — projektin juuressa
|
||||
#
|
||||
# Pakolliset osiot: docker (jos master-branch buildaa kontin), test-flow (jos ketjutetaan)
|
||||
# Vapaaehtoiset: sonarqube, deployment
|
||||
|
||||
docker:
|
||||
registry: gitea # gitea | artifactory | nexus (MVP: vain gitea)
|
||||
imageName: temperature-store # kontin nimi, pakollinen
|
||||
|
||||
sonarqube:
|
||||
url: https://sonar.example.com
|
||||
projectKey: temperature-store
|
||||
|
||||
deployment:
|
||||
jobName: deploy # deploy-workflown nimi (vakio)
|
||||
projectFolder: microservices # polku Helm-repossa
|
||||
fileName: values-{.environment}.yaml
|
||||
property: container.version
|
||||
|
||||
test-flow:
|
||||
- deploy: development # 1. deploy development-ympäristöön
|
||||
wait: true # odota deployn valmistumista
|
||||
|
||||
- test:
|
||||
name: "integration fast"
|
||||
environment: integration
|
||||
repo: tests/integration # testi-repo (owner/repo)
|
||||
workflow: test.yml # workflow-tiedosto testi-repossa
|
||||
ref: main # branch
|
||||
tags: "@temperature and not @slow"
|
||||
|
||||
- deploy: staging
|
||||
wait: true
|
||||
|
||||
- test:
|
||||
name: e2e
|
||||
environment: staging
|
||||
repo: tests/e2e
|
||||
workflow: test.yml
|
||||
ref: main
|
||||
tags: "@e2e and not @slow"
|
||||
```
|
||||
|
||||
### Kenttäkuvaukset
|
||||
|
||||
#### `docker`
|
||||
|
||||
| Kenttä | Pakollinen | Kuvaus |
|
||||
|--------|------------|--------|
|
||||
| `registry` | Ei (oletus `gitea`) | Rekisterityyppi. MVP: `gitea`. Factory/adapter-pattern avaa `artifactory`, `nexus` myöhemmin |
|
||||
| `imageName` | Kyllä | Kontin nimi. Lopullinen tagi: `{gitea_host}/{owner}/{imageName}:{version}.{run_number}` |
|
||||
|
||||
#### `sonarqube`
|
||||
|
||||
| Kenttä | Pakollinen | Kuvaus |
|
||||
|--------|------------|--------|
|
||||
| `url` | Kyllä | SonarQube-palvelimen URL |
|
||||
| `projectKey` | Kyllä | SonarQube-projektin avain |
|
||||
|
||||
SonarQube-token tulee Gitea org secretsista (`SONAR_TOKEN`). Ei `creditentials`-viittausta.
|
||||
|
||||
#### `deployment`
|
||||
|
||||
| Kenttä | Pakollinen | Kuvaus |
|
||||
|--------|------------|--------|
|
||||
| `jobName` | Ei (oletus `deploy`) | Deploy-workflown tiedostonimi ilman `.yml`-päätettä |
|
||||
| `projectFolder` | Kyllä | Polku mikropalvelun kansioon Helm-repossa |
|
||||
| `fileName` | Kyllä | YAML-tiedoston nimi. `{.environment}` korvataan ympäristön nimellä |
|
||||
| `property` | Kyllä | Päivitettävä avain (piste-eroteltu polku, esim. `container.version`) |
|
||||
|
||||
Deploy-token (kirjoitusoikeus Helm-repoon) tulee Gitea org secretsista (`DEPLOY_TOKEN`).
|
||||
|
||||
#### `test-flow`
|
||||
|
||||
Array testi-steppejä. Jokainen steppi on joko `deploy` tai `test`.
|
||||
|
||||
**`deploy`-steppi:**
|
||||
|
||||
| Kenttä | Pakollinen | Kuvaus |
|
||||
|--------|------------|--------|
|
||||
| `deploy` | Kyllä | Ympäristön nimi (esim. `development`, `staging`) |
|
||||
| `wait` | Ei (oletus `true`) | Odotetaanko deployn valmistumista ennen seuraavaa steppiä |
|
||||
|
||||
**`test`-steppi:**
|
||||
|
||||
| Kenttä | Pakollinen | Kuvaus |
|
||||
|--------|------------|--------|
|
||||
| `name` | Kyllä | Testivaiheen nimi (näkyy statusviestissä) |
|
||||
| `environment` | Kyllä | Ympäristö jota vasten testataan |
|
||||
| `repo` | Kyllä | Testi-repo muodossa `owner/repo` |
|
||||
| `workflow` | Kyllä | Workflow-tiedosto testi-repossa |
|
||||
| `ref` | Kyllä | Branch (esim. `main`) |
|
||||
| `tags` | Ei | Cucumber-tagit (esim. `"@smoke and not @slow"`) |
|
||||
| `versionApiUrl` | Ei | URL deployed-version tarkistukseen |
|
||||
| `versionCheckScript` | Ei | Polku version check -skriptiin (repossa tai kontissa) |
|
||||
|
||||
---
|
||||
|
||||
## `isArtifactBuild()`-mekanismi (POC: suunniteltu, ei toteutettu)
|
||||
|
||||
> **Jenkins-legacy:** Jenkins-versiossa tämä oli `isContainerBuild()`. POC
|
||||
> osoitti, että provider ei tiedä eikä tarvitse tietää, buildaako consumer
|
||||
> kontin, JARin vai npm-paketin. Siksi `isContainerBuild()` →
|
||||
> `isArtifactBuild()`.
|
||||
|
||||
**Ongelma:** Samaa committia vasten voidaan ajaa master-workflow useita
|
||||
kertoja. On mieletöntä buildata artifakti uudestaan, koska commit on jo
|
||||
tagätty versiolla ja artifakti on olemassa rekisterissä. Uudelleenbuildaus
|
||||
aiheuttaa versiokonflikteja ja tuhlaa CI-aikaa.
|
||||
|
||||
**Ratkaisu:** Workflow'n alussa tarkistetaan, onko tälle commitille jo
|
||||
olemassa versiotagi.
|
||||
|
||||
```bash
|
||||
# is-container-built.sh
|
||||
TAG=$(git tag --points-at HEAD | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -1)
|
||||
if [ -n "$TAG" ]; then
|
||||
echo "container_already_built=true" >> $GITHUB_ENV
|
||||
echo "container_version=$TAG" >> $GITHUB_ENV
|
||||
else
|
||||
echo "container_already_built=false" >> $GITHUB_ENV
|
||||
fi
|
||||
```
|
||||
|
||||
Workflow käyttää tätä ehtona:
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
build-container:
|
||||
if: env.container_already_built != 'true'
|
||||
steps:
|
||||
- run: docker build ...
|
||||
test-flow:
|
||||
if: always()
|
||||
needs: [build-container]
|
||||
steps:
|
||||
- run: dispatch-workflow.sh ...
|
||||
```
|
||||
|
||||
**Mitä `isContainerBuild() == true` tarkoittaa käytännössä:**
|
||||
- Kontti on jo buildattu ja pushattu rekisteriin
|
||||
- Commit on tagätty versiolla (esim. `1.2.3.42`)
|
||||
- Build-steppi skipataan → siirrytään suoraan test flow'hun
|
||||
- Sama versio deployataan ja testataan — ei uutta konttia
|
||||
|
||||
**Miksi tämä on välttämätöntä:**
|
||||
- Estää versiokonfliktit: `1.2.3.42` ei voi olla kahdesti
|
||||
- Säästää CI-aikaa: artifaktin buildaus on hitain vaihe
|
||||
- Pitää commitin ja artifaktin välisen suhteen yksiselitteisenä: `git tag` kertoo suoraan mikä versio vastaa tätä committia
|
||||
|
||||
---
|
||||
|
||||
## Version check (Fibonacci-backoff)
|
||||
|
||||
Ennen kuin testit ajetaan, pitää varmistua että haluttu konttiversio on oikeasti deployattu ympäristöön. Muuten testataan väärää versiota.
|
||||
|
||||
**Malli:** Skripti, joka pollaa deployatun version API:a Fibonacci-backoffilla:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# check-version.sh <version_api_url> <expected_version>
|
||||
# Palauttaa 0 jos versiot täsmäävät, 1 muuten.
|
||||
|
||||
URL=$1
|
||||
EXPECTED=$2
|
||||
MAX_RETRIES=10
|
||||
|
||||
# Fibonacci-sekvenssi: 1 2 3 5 8 13 21 34 55 89
|
||||
FIB=(1 2 3 5 8 13 21 34 55 89)
|
||||
|
||||
for i in $(seq 1 $MAX_RETRIES); do
|
||||
ACTUAL=$(curl -s "$URL" | jq -r '.version // empty')
|
||||
if [ "$ACTUAL" = "$EXPECTED" ]; then
|
||||
echo "Version match: $ACTUAL"
|
||||
exit 0
|
||||
fi
|
||||
echo "Attempt $i/$MAX_RETRIES: $ACTUAL != $EXPECTED, waiting ${FIB[$i-1]}s..."
|
||||
sleep ${FIB[$i-1]}
|
||||
done
|
||||
|
||||
echo "Version mismatch after $MAX_RETRIES attempts"
|
||||
exit 1
|
||||
```
|
||||
|
||||
**Miksi Fibonacci:** Uusi deploy käynnistyy nopeasti (ensimmäiset pollaukset tiheään). Jos kontin pullaus tai podin käynnistys kestää, pollausväli kasvaa — ei turhaan kuormiteta API:a. Maksimiaika: ~231 sekuntia (summa 1..89).
|
||||
|
||||
Version check -skripti joko:
|
||||
- Asuu testi-repossa (projektin oma toteutus) → `versionCheckScript`-kenttä
|
||||
- Tai käyttää geneeristä API:a → `versionApiUrl`-kenttä, skripti on osa kirjastoa
|
||||
|
||||
---
|
||||
|
||||
## `doNotDowngrade`
|
||||
|
||||
Jenkinsin deploy-jobissa oli `doNotDowngrade`-parametri, joka esti vanhemman version deployaamisen uudemman päälle. Gitea Actions -versiossa:
|
||||
|
||||
- **Ei MVP:ssä.** Deploy tekee sen mitä käsketään. `doNotDowngrade` on lisäturva, joka voidaan lisätä deploy-workflow'hun myöhemmin.
|
||||
- **Mekanismi:** Ennen YAML:n muokkausta tarkistetaan nykyinen versio. Jos `new < current`, skipataan ja raportoidaan.
|
||||
- **Toteutus:** Yksi `if`-ehto deploy-workflow'n alussa, ei vaadi muutoksia muualle.
|
||||
|
||||
---
|
||||
|
||||
## UX-esimerkki: projektin `.gitea/workflows/ci.yml`
|
||||
|
||||
Näin mikropalvelun kehittäjä käyttää kirjastoa:
|
||||
|
||||
```yaml
|
||||
# .gitea/workflows/ci.yml — projektin juuressa
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
feature:
|
||||
if: github.ref != 'refs/heads/master'
|
||||
uses: org/gitea-ci-library/.gitea/workflows/ci-feature.yml@v1
|
||||
load-config:
|
||||
uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@main
|
||||
secrets: inherit
|
||||
with:
|
||||
config-file: ci-flow-values.yaml
|
||||
maven-image: maven:3.9-eclipse-temurin-21
|
||||
|
||||
master:
|
||||
if: github.ref == 'refs/heads/master'
|
||||
uses: org/gitea-ci-library/.gitea/workflows/ci-master.yml@v1
|
||||
secrets: inherit
|
||||
with:
|
||||
config-file: ci-flow-values.yaml
|
||||
maven-image: maven:3.9-eclipse-temurin-21
|
||||
docker-image: docker:26-dind
|
||||
config_path: .gitea/workflows/gitea-env.conf
|
||||
```
|
||||
|
||||
Kehittäjä määrittelee:
|
||||
- Millä kontilla buildataan (`maven-image` — koska kirjasto ei tiedä projektin Java-versiota)
|
||||
- Mistä konfiguraatio luetaan (`config-file`)
|
||||
- Millä docker-versiolla kontit rakennetaan (`docker-image`)
|
||||
---
|
||||
|
||||
Kaikki Git-, raportointi-, SonarQube- ja deploy-konfiguraatio on `ci-flow-values.yaml`:ssa.
|
||||
## `check-version.yml` — version päättely
|
||||
|
||||
Provider-workflow joka etsii version prioriteettijärjestyksessä:
|
||||
|
||||
1. `VERSION`-tiedosto (plain text, esim. `0.2`)
|
||||
2. `package.json` → `.version`-kenttä (Node.js)
|
||||
3. `pom.xml` → `<version>`-elementti (Maven)
|
||||
|
||||
Hakee git-tagit Gitea API:sta ja laskee seuraavan vapaan patch-version.
|
||||
|
||||
**Output:** `artifact_exists` (true/false), `version` (string)
|
||||
|
||||
**Idempotentti:** Jos commitilla on jo versiotagi, `artifact_exists=true` ja
|
||||
build-vaiheet skipataan. Samaa committia ei buildata kahdesti.
|
||||
|
||||
---
|
||||
|
||||
## `env_json`-propagointi
|
||||
|
||||
```
|
||||
gitea-env.conf → config-provider.yml → env_json (JSON-string)
|
||||
↓
|
||||
ci.yml with: env_json → kaikki downstream-workflowt
|
||||
```
|
||||
|
||||
Jokainen provider-workflow purkaa tarvitsemansa arvot `fromJson(inputs.env_json).KEY`:lla.
|
||||
Consumerin ei tarvitse tietää mitä avaimia kukin provider käyttää.
|
||||
|
||||
Reference in New Issue
Block a user