Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions .github/workflows/clients-ruby.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: "Clients Ruby"

on:
push:
branches: ['**']
paths:
- 'clients/ruby/**'
- 'commons/swagger/**'
- '.github/workflows/clients-ruby.yml'
tags:
- 'ruby-api-*-v*'

jobs:
rspec:
name: RSpec (Ruby ${{ matrix.ruby }})
if: github.ref_type != 'tag'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby: ['3.2', '3.3', '4.0']
steps:
- uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- name: commons
working-directory: clients/ruby/commons
run: bundle install && bundle exec rspec
- name: api_entreprise
working-directory: clients/ruby/api_entreprise
run: bundle install && bundle exec rspec
- name: api_particulier
working-directory: clients/ruby/api_particulier
run: bundle install && bundle exec rspec

freshness:
name: sync_commons & scaffold_resources freshness
if: github.ref_type != 'tag'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
- name: Verify vendored commons is up to date
run: clients/ruby/bin/sync_commons --check
- name: Verify scaffolded resources are up to date
run: clients/ruby/bin/scaffold_resources --api all --check

release:
name: Build & push to rubygems.org
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
environment: rubygems
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v6

- name: Resolve gem from tag
id: gem
run: |
case "$GITHUB_REF_NAME" in
ruby-api-entreprise-v*)
echo "name=api_entreprise" >>"$GITHUB_OUTPUT"
echo "dir=clients/ruby/api_entreprise" >>"$GITHUB_OUTPUT"
;;
ruby-api-particulier-v*)
echo "name=api_particulier" >>"$GITHUB_OUTPUT"
echo "dir=clients/ruby/api_particulier" >>"$GITHUB_OUTPUT"
;;
*)
echo "Unsupported tag: $GITHUB_REF_NAME" >&2
exit 1
;;
esac

- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: ${{ steps.gem.outputs.dir }}

- name: Verify tag version matches gemspec version
working-directory: ${{ steps.gem.outputs.dir }}
run: |
tag_version="${GITHUB_REF_NAME##*-v}"
gem_version=$(ruby -e 'puts Gem::Specification.load("${{ steps.gem.outputs.name }}.gemspec").version')
if [ "$tag_version" != "$gem_version" ]; then
echo "Tag version '$tag_version' does not match gemspec version '$gem_version'" >&2
exit 1
fi
echo "Releasing ${{ steps.gem.outputs.name }} $gem_version"

- name: Run rspec
working-directory: ${{ steps.gem.outputs.dir }}
run: bundle exec rspec

- uses: rubygems/release-gem@v1
with:
working-directory: ${{ steps.gem.outputs.dir }}
95 changes: 95 additions & 0 deletions clients/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# clients/

Familles de SDKs officiels pour [API Entreprise v3](https://entreprise.api.gouv.fr)
et [API Particulier v3](https://particulier.api.gouv.fr), construites au-dessus
des specs OpenAPI versionnées dans [`commons/swagger/`](../commons/swagger).

## Ce qui est ici

| Fichier / dossier | Rôle |
|---|---|
| [`SPECS.md`](./SPECS.md) | Contrat normatif (langage-agnostique) que tout client doit respecter : environnements, auth, enveloppe, erreurs, rate-limit, testing, packaging, checklist de conformité. |
| `ruby/` | Implémentation de référence en Ruby. |
| `node/`, `python/`, `php/`, `java/` | *(à venir)* — ports à produire en suivant `SPECS.md` et en s'inspirant de `ruby/`. |

## L'implémentation de référence : `ruby/`

```
ruby/
commons/ # source de vérité partagée (Configuration, Response,
# RateLimit, hiérarchie d'erreurs JSON:API, SIRET/SIREN
# validators, Faraday middlewares, ClientBase, …)
api_entreprise/ # gem publié — 23 resources scaffoldées par provider
api_particulier/ # gem publié — 9 resources scaffoldées par provider
bin/sync_commons # vendorise commons/ dans chaque gem en réécrivant le
# namespace (ApiGouvCommons → ApiEntreprise::Commons …)
bin/scaffold_resources # (re)génère les lib/*/resources/*.rb depuis les specs
# OpenAPI de commons/swagger/
```

Le dossier `commons/` **n'est pas publié** comme gem. Chaque gem embarque sa
propre copie vendorisée — pas de couplage au moment du release. `bin/sync_commons`
garde les copies en phase ; la CI vérifie la fraîcheur avec `--check`.

### Lancer les tests localement

```sh
cd clients/ruby/commons && bundle && bundle exec rspec # 65 / 65
cd clients/ruby/api_entreprise && bundle && bundle exec rspec # 32 / 32
cd clients/ruby/api_particulier && bundle && bundle exec rspec # 18 / 18
```

### Exemples (lancés sans réseau grâce à WebMock, sauf les `basic.rb`)

```sh
cd clients/ruby/api_entreprise
bundle exec ruby examples/error_handling.rb # matrice d'exceptions complète
bundle exec ruby examples/retry.rb # retry opt-in sur 429 / 502 / 503

cd ../api_particulier
bundle exec ruby examples/error_handling.rb
bundle exec ruby examples/retry.rb
```

Les `examples/basic.rb` de chaque gem tapent sur le bac à sable staging et
requièrent un jeton :

```sh
TOKEN=$(curl -s https://raw.githubusercontent.com/datagouv/apistration/develop/mocks/tokens/default)
API_ENTREPRISE_TOKEN=$TOKEN bundle exec ruby clients/ruby/api_entreprise/examples/basic.rb
API_PARTICULIER_TOKEN=$TOKEN bundle exec ruby clients/ruby/api_particulier/examples/basic.rb
```

Pour un run de conformité complet contre staging avant release, suivre
[`TESTING.md`](TESTING.md) — c'est la playbook qui remplace les anciens
`bin/smoke` (trop superficiels pour catcher autre chose qu'une panne infra).

### Régénérer après un changement de spec OpenAPI

```sh
clients/ruby/bin/sync_commons
clients/ruby/bin/scaffold_resources --api all
```

## Porter SPECS.md dans une autre langue

1. Lire `SPECS.md` du début à la fin — il est normatif et langage-agnostique.
2. Calquer la structure ruby/ : un sous-dossier `commons/` pour le code
partagé, un dossier par gem publié, des scripts de build qui vendorisent
`commons/` dans chaque artefact.
3. Couvrir la matrice de tests unitaires §12.1 (validateurs SIRET/SIREN,
configuration immuable, auth strategy, enveloppe, mapping d'erreurs,
rate-limit, retry, redaction des logs PII, signatures des resources).
4. Couvrir les 4 cas bout-en-bout §12.2 (200, 422, 429 avec `retry_after`,
502 avec `meta.retry_in`) contre un stub HTTP.
5. Publier un README avec un exemple de stub, un `CHANGELOG.md`.
6. Cocher la checklist §20 avant merge.

## CI

[`.github/workflows/clients-ruby.yml`](../.github/workflows/clients-ruby.yml)
lance sur chaque push :

- `rspec` pour les 3 projets Ruby sur la matrice Ruby 3.2 / 3.3 / 4.0
- `bin/sync_commons --check` (échoue si commons vendorisé pas en phase)
- `bin/scaffold_resources --api all --check` (échoue si resources obsolètes)
Loading
Loading