From db1342685ca31ebda6e6d647e5c1d27508989ff8 Mon Sep 17 00:00:00 2001 From: moilanik Date: Tue, 16 Jun 2026 06:01:29 +0300 Subject: [PATCH] =?UTF-8?q?t=C3=A4gitys=20k=C3=A4ytt=C3=B6=C3=B6n=20consum?= =?UTF-8?q?er=20viittauksessa=20provider=20tiedostoihin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/example-main.yml | 9 ++- .gitea/workflows/tag-maintenance.yml | 38 +++++++++++ CURRENT_PROVIDER_VERSION | 1 + README.md | 2 + docs/adr/0009-breaking-changes-forbidden.md | 53 +++++++++++++++ docs/adr/0010-pipeline-router-no-commands.md | 43 +++++++++++++ docs/config-model.md | 2 +- docs/consumer-guide.md | 68 ++++++++++++++++++-- 8 files changed, 208 insertions(+), 8 deletions(-) create mode 100644 .gitea/workflows/tag-maintenance.yml create mode 100644 CURRENT_PROVIDER_VERSION create mode 100644 docs/adr/0009-breaking-changes-forbidden.md create mode 100644 docs/adr/0010-pipeline-router-no-commands.md diff --git a/.gitea/workflows/example-main.yml b/.gitea/workflows/example-main.yml index 0043455..81d7ca6 100644 --- a/.gitea/workflows/example-main.yml +++ b/.gitea/workflows/example-main.yml @@ -53,9 +53,16 @@ jobs: report-summary: name: Report Summary - needs: [load-config, bats, cucumber] + needs: [load-config, build-push] if: always() uses: niko/gitea-ci-library/.gitea/workflows/example-report-summary.yml@main with: env_json: ${{ needs.load-config.outputs.env_json }} suites: bats cucumber + + tag-maintenance: + name: Move provider version tag + needs: [build-push] + if: success() + uses: niko/gitea-ci-library/.gitea/workflows/tag-maintenance.yml@main + secrets: inherit diff --git a/.gitea/workflows/tag-maintenance.yml b/.gitea/workflows/tag-maintenance.yml new file mode 100644 index 0000000..1e8f5a2 --- /dev/null +++ b/.gitea/workflows/tag-maintenance.yml @@ -0,0 +1,38 @@ +name: Tag Maintenance +on: + workflow_call: + secrets: + GITEA_TOKEN: + required: true + +jobs: + move-tag: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Read current provider version + id: version + run: echo "TAG=$(cat CURRENT_PROVIDER_VERSION | tr -d '[:space:]')" >> "$GITHUB_OUTPUT" + + - name: Move tag to commit + run: | + TAG="${{ steps.version.outputs.TAG }}" + SHA="${{ github.sha }}" + + curl -sf -X DELETE \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + "${{ gitea.server_url }}/api/v1/repos/${{ github.repository }}/tags/${TAG}" || true + + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + -H "Content-Type: application/json" \ + "${{ gitea.server_url }}/api/v1/repos/${{ github.repository }}/tags" \ + -d "{\"tag_name\": \"${TAG}\", \"message\": \"Release ${TAG}\", \"target\": \"${SHA}\"}") + + if [ "$HTTP_CODE" = "201" ]; then + echo "${TAG} tag moved to ${SHA}" + else + echo "ERROR: failed to move ${TAG} tag (HTTP $HTTP_CODE)" >&2 + exit 1 + fi diff --git a/CURRENT_PROVIDER_VERSION b/CURRENT_PROVIDER_VERSION new file mode 100644 index 0000000..626799f --- /dev/null +++ b/CURRENT_PROVIDER_VERSION @@ -0,0 +1 @@ +v1 diff --git a/README.md b/README.md index 41130ae..517bdf5 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Reusable workflow -kirjasto Gitea Actionsille. Lisätietoja: [docs/](docs/) +**Consumer-käyttöönotto:** [docs/consumer-guide.md](docs/consumer-guide.md) — vaiheittainen ohje uuden projektin liittämiseen + ## Provider-binding — miten consumer löytää providerin Consumer kutsuu provideria `uses:`-viittauksella. Ei discoveryä — polku kovakoodataan consumerin diff --git a/docs/adr/0009-breaking-changes-forbidden.md b/docs/adr/0009-breaking-changes-forbidden.md new file mode 100644 index 0000000..dcc8623 --- /dev/null +++ b/docs/adr/0009-breaking-changes-forbidden.md @@ -0,0 +1,53 @@ +# 9. Breaking changes kielletty + +## Päätös + +Providerin `v1`-tagin osoittamaa rajapintaa ei koskaan rikota. +Consumerin `uses:`-kutsut säilyvät yhteensopivina — uusi versiotagi +(`v2`, `v3`) luodaan VAIN jos taaksepäin yhteensopimaton muutos on +pakottava. Käytännössä: `v1` on pysyvä, ja sitä ylläpidetään +eteenpäin. + +## Rajapinnan määritelmä + +Providerin rajapinta = `config-provider.yml` ja `check-version.yml` +workflow_call-inputit ja -outputit: + +- Inputtien nimet, tyypit ja required-arvot eivät muutu +- Outputtien nimet eivät katoa +- Secret-nimet eivät muutu +- Workflow-tiedoston nimi ja polku eivät muutu + +Sisäinen toteutus (scriptit, checkout-logiikka, build-vaiheet) voi +muuttua vapaasti — consumer ei ole niistä riippuvainen. + +## Versiotagin siirto + +Tagi `v1` siirretään automaattisesti uusimpaan onnistuneeseen +main-commitin CI-ajoon (`tag-maintenance.yml`). Tagin nimi luetaan +tiedostosta `CURRENT_PROVIDER_VERSION`. + +Jos breaking change joskus tulee pakottavaksi: +1. Päivitä `CURRENT_PROVIDER_VERSION` → `v2` +2. Luo uusi `v2`-tagi manuaalisesti (osoittaa uuteen rajapintaan) +3. `tag-maintenance.yml` alkaa ylläpitää `v2`:ta eteenpäin +4. `v1`-tagia **ei poisteta** — se jää osoittamaan viimeistä + v1-yhteensopivaa committia. `v1`:tä käyttävät consumerit + jatkavat toimintaansa ilman muutoksia. +5. Uudet consumerit ottavat käyttöön `@v2`:n. + +Aktiivisesti ylläpidetään vain yhtä tagia (`CURRENT_PROVIDER_VERSION`). +Vanhat tagit säilyvät paikoillaan taaksepäin yhteensopivuutta varten. + +## Perustelu + +Yhden aktiivisen tagin ylläpito on yksinkertaisempaa kuin usean +rinnakkaisen version aktiivinen hallinta. Homelab-ympäristössä +consumerit ovat saman ylläpitäjän hallinnassa — eri tiimien +rinnakkaisia aktiiviversioita ei tarvita. + +Breaking changen sattuessa vanha tagi säilyy — vanhat consumerit +eivät hajoa. Uusi tagi otetaan käyttöön uusissa consumereissa. + +Breaking changen kielto pakottaa suunnittelemaan rajapinnat +huolellisesti etukäteen. diff --git a/docs/adr/0010-pipeline-router-no-commands.md b/docs/adr/0010-pipeline-router-no-commands.md new file mode 100644 index 0000000..ea7e63e --- /dev/null +++ b/docs/adr/0010-pipeline-router-no-commands.md @@ -0,0 +1,43 @@ +# 10. Pipeline-reititin — ei komentoja + +## Päätös + +CI-pipelinetiedostot (`ci-main.yml`, `ci-feature.yml`) ovat puhtaita +**reitittimiä**. Ne eivät saa sisältää `run:`-komentoja, inline-skriptejä +tai varsinaista build-/test-logiikkaa. Niiden ainoa sallittu sisältö on: + +- `uses:` — viittaus reusable workflow'hun +- `needs:` — riippuvuus toisen jobin valmistumiseen +- `if:` — ehdollinen suoritus +- `secrets: inherit` — salaisuuksien välitys + +## Mikä ei kuulu reitittimeen + +- `run:`-komennot +- Inline-skriptit (shell, Python, tms.) +- `actions/checkout` (paitsi providerin sisäinen infrastruktuuri) +- Build-työkalut, testikomennot, Docker-komennot +- Raporttien generointi + +## Missä logiikka on + +| Kerros | Tiedosto | Sisältö | +|---|---|---| +| Reititin | `ci-main.yml`, `ci-feature.yml` | Vain `uses:`-kutsut | +| Workflow_call | `ci-unit-tests.yml`, `ci-acc-tests.yml`, … | Varsinainen testi-/build-logiikka | +| Provider | `config-provider.yml`, `check-version.yml`, … | Jaettu infrastruktuuri | +| Skriptit | `scripts/` | Apufunktiot (status, publish, validointi) | + +## Perustelu + +Reitittimen ja toteutuksen erottelu: + +- Reititin kertoo **mitä** ajetaan ja **missä järjestyksessä** — luettavissa + yhdellä silmäyksellä ilman teknistä taustaa +- Toteutus (workflow_call) kertoo **miten** — tekninen henkilö voi keskittyä + yhteen tiedostoon kerrallaan +- Providerin reusable workflow't eivät koskaan sisällä inline-logiikkaa — + skriptit ovat omissa tiedostoissaan + +Tämä on sama periaate kuin web-sovelluksissa: reititin ei sisällä +business-logiikkaa, vain HTTP-verbit ja polut. diff --git a/docs/config-model.md b/docs/config-model.md index 5b41f5b..0f7503f 100644 --- a/docs/config-model.md +++ b/docs/config-model.md @@ -87,7 +87,7 @@ JSON-muotoisen `env_json`:n. Kutsu: ```yaml load-config: - uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@main + uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@v1 secrets: inherit with: config_path: .gitea/workflows/gitea-env.conf diff --git a/docs/consumer-guide.md b/docs/consumer-guide.md index 9d60fe5..aabff78 100644 --- a/docs/consumer-guide.md +++ b/docs/consumer-guide.md @@ -137,7 +137,7 @@ on: jobs: load-config: - uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@main + uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@v1 secrets: inherit with: config_path: .gitea/workflows/gitea-env.conf @@ -159,7 +159,7 @@ jobs: report-summary: needs: [load-config, unit-tests, acc-tests] if: always() - uses: org/gitea-ci-library/.gitea/workflows/report-summary.yml@main + uses: org/gitea-ci-library/.gitea/workflows/report-summary.yml@v1 with: env_json: ${{ needs.load-config.outputs.env_json }} suites: junit cucumber @@ -181,14 +181,14 @@ on: jobs: load-config: - uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@main + uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@v1 secrets: inherit with: config_path: .gitea/workflows/gitea-env.conf check-version: needs: [load-config] - uses: org/gitea-ci-library/.gitea/workflows/check-version.yml@main + uses: org/gitea-ci-library/.gitea/workflows/check-version.yml@v1 secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} @@ -212,7 +212,7 @@ jobs: build-push: needs: [load-config, check-version, unit-tests, acc-tests] if: needs.check-version.outputs.artifact_exists != 'true' - uses: org/gitea-ci-library/.gitea/workflows/docker-build-push.yml@main + uses: org/gitea-ci-library/.gitea/workflows/docker-build-push.yml@v1 secrets: inherit with: env_json: ${{ needs.load-config.outputs.env_json }} @@ -221,7 +221,7 @@ jobs: report-summary: needs: [load-config, unit-tests, acc-tests] if: always() - uses: org/gitea-ci-library/.gitea/workflows/report-summary.yml@main + uses: org/gitea-ci-library/.gitea/workflows/report-summary.yml@v1 with: env_json: ${{ needs.load-config.outputs.env_json }} suites: junit cucumber @@ -388,3 +388,59 @@ hajota vanhemmilla versioilla. | `report-status.sh` | POSTaa commit-statuksen linkillä | | `publish-git-pages.sh` | Julkaisee raporttihakemiston git-pagesiin | | `ci-validate.sh` | Validoi `.conf`-tiedoston (kutsutaan `config-provider.yml`:stä) | + +--- + +## ADR-yhteenveto — consumerin kannalta oleelliset säännöt + +Nämä säännöt on formalisoitu [docs/adr/](docs/adr/)-hakemistossa. Tässä tiivistelmä +consumer-näkökulmasta: + +### Reititin ei sisällä suorittavaa koodia (ADR 0010) + +`ci-feature.yml` ja `ci-main.yml` ovat **puhtaita reitittimiä**: +- **Vain** `uses:`, `needs:` ja `if:` sallittu +- **Ei** `run:`-komentoja, ei inline-skriptejä, ei `actions/checkout` + +Kaikki suorittava koodi on omissa `workflow_call`-tiedostoissaan: +- `ci-unit-tests.yml` — testikomento, publish, status +- `ci-acc-tests.yml` — testikomento, publish, status +- Provider-workflowt (`config-provider.yml`, `check-version.yml`, …) + +### Yksi steppi = yksi workflow_call-tiedosto + +Jokainen pipeline-steppi (testityyppi, build, deploy) on oma tiedostonsa. +Ei kahta eri komentoa samassa workflow'ssa. Tämä pitää reitittimet ohuina +ja steppitiedostot itsenäisinä — testattavissa erikseen. + +### Provider-versio on `@v1` (ADR 0009) + +Kaikki `org/gitea-ci-library/…`-viittaukset käyttävät `@v1`-tagia: +```yaml +uses: org/gitea-ci-library/.gitea/workflows/config-provider.yml@v1 +``` +`@main` on vain providerin oman repon sisäiseen dogfood-käyttöön. + +Breaking changet on kielletty — `v1`-rajapinta on pysyvä. + +### Exit-koodi on ainoa onnistumisen mittari (ADR 0008) + +Älä käytä pipeä (`|`) komennon perässä — se syö exit-koodin. +Käytä redirectiä (`> file 2>&1`) jos haluat logit talteen. + +### Commit-status vain raporttilinkille (ADR 0007) + +`report-status.sh`-skriptiä käytetään VAIN kun on raportti linkitettäväksi. +Tool-jobit (build, deploy) luottavat Gitean natiiviin job-statukseen. + +### Providerin checkout ei kuulu consumerille + +Providerin scriptit haetaan `actions/checkout`-stepillä. Consumer käyttää +providerin määrittelemää polkua (`.ci/scripts/`). Consumer ei kopioi eikä +muokkaa providerin tiedostoja. + +### Testattavuus + +Jokainen `workflow_call`-tiedosto on testattavissa itsenäisesti — consumer +voi ajaa `ci-unit-tests.yml`:n paikallisesti act:lla tai Gitean +`workflow_dispatch`:llä ilman koko pipelineä.