Release a new SDK version
Source of truth for Ruby : clients/ruby/README.md
§"Publier une version sur rubygems.org". Read it before deviating.
Scope
One gem at a time. api_entreprise and api_particulier versionnent
indépendamment — ne jamais coupler les deux dans une même release.
Prérequis par gem (à valider au moins une fois)
Ces points sont des prérequis externes au repo. Si l'un manque, le
workflow échoue de façon souvent silencieuse ou cryptique. Vérifier
avant de pousser un tag sur un gem qui n'a jamais été release via le
workflow.
Trusted publisher OIDC sur rubygems —
https://rubygems.org/profile/oidc/trusted_publishers doit avoir une
entrée pour le gem avec exactement :
- GitHub Repository :
datagouv/apistration
- Workflow Filename :
clients-ruby.yml (pas clients-ruby-release.yml,
pas autre chose — doit matcher le nom de fichier sous
.github/workflows/)
- Environment :
rubygems
Mismatch → erreur explicite à l'étape configure-rubygems-credentials :
No trusted publisher configured for this workflow found on https://rubygems.org for audience rubygems.org.
Branch policy de l'environment rubygems typée tag (cf. Gotchas).
Rakefile + rake dev dep dans le gem
(clients/ruby/<gem>/Rakefile + gem 'rake' dans le Gemfile group
:development). Le Rakefile doit require 'bundler/gem_tasks' et,
pour fonctionner avec rubygems/release-gem@v1, no-op
release:source_control_push quand CI=true (cf. Rakefile en place).
Sans Rakefile : can't find executable rake for gem rake.
Premier release manuel déjà effectué pour réserver le nom du gem
sur rubygems (cf. clients/ruby/README.md §Prérequis).
Workflow (Ruby)
Branche release dédiée
git checkout -b release/api-<entreprise|particulier>-<X.Y.Z>
Bump clients/ruby/<gem>/lib/<gem>/version.rb. SemVer :
- patch : régénération scaffolding, changement OpenAPI rétro-compatible
(paramètre devient optionnel, nouveau champ de réponse).
- minor : nouvel endpoint, nouvelle méthode publique.
- major : breaking change (paramètre requis ajouté, méthode supprimée,
renommage).
CHANGELOG clients/ruby/<gem>/CHANGELOG.md — format Keep a Changelog :
- Convertir
[Unreleased] en [X.Y.Z] - YYYY-MM-DD quand la section
contient le contenu releasé, sinon ajouter une nouvelle section
[X.Y.Z] au-dessus de [Unreleased] (qui reste vide).
- Sections :
Added / Changed / Deprecated / Removed / Fixed /
Security. Référencer le SHA upstream qui motive la release.
Tests locaux
cd clients/ruby/<gem> && bundle exec rspec
Le Gemfile.lock est modifié par le bundle (<gem> (X.Y.Z)) — l'inclure
dans le commit.
Commit unique
git commit -m "Release <gem> X.Y.Z"
Message détaillé sur le pourquoi (changement upstream, breaking, etc.).
PR vers develop — review obligatoire, squash-merge.
Tag le commit de merge sur develop (pas la branche release jetable —
sinon le tag pointe sur un commit orphelin) :
git checkout develop && git pull
git tag ruby-api-<entreprise|particulier>-v<X.Y.Z>
git push origin ruby-api-<entreprise|particulier>-v<X.Y.Z>
Workflow .github/workflows/clients-ruby.yml se déclenche sur le tag :
- vérifie
tag_version == gemspec.version ;
- relance rspec ;
- publie via
rubygems/release-gem@v1 (OIDC trusted publisher, environment
rubygems).
Surveiller la run, vérifier la version sur rubygems.org après succès.
Tags reconnus
| Tag |
Gem publié |
ruby-api-entreprise-v<X.Y.Z> |
api_entreprise |
ruby-api-particulier-v<X.Y.Z> |
api_particulier |
Tag invalide → step "Resolve gem from tag" échoue et stoppe le workflow.
Gotchas
- Tag mal placé (sur la branche release jetable non mergée) : le commit n'est
atteignable depuis aucune branche permanente. Toujours tagger après merge,
sur
develop.
- Version dans
version.rb ≠ tag : le job release échoue à
"Verify tag version matches gemspec version".
- Ne jamais committer
Gemfile.lock sans avoir bumpé version.rb avant —
divergence silencieuse.
- Le
CHANGELOG.md initial des gems publiait le contenu sous [Unreleased]
alors que 0.1.0 était déjà sur rubygems. Au premier patch, convertir
[Unreleased] → [0.1.0] puis ajouter [0.1.1] au-dessus.
- Branch policy de l'environment
rubygems doit être de type tag, pas
branch. Si la policy ruby-api-<gem>-v* est typée branch (cas
rencontré sur api_particulier à la 0.1.1), GitHub rejette le déploiement
instantanément : zéro step exécuté, log introuvable (log not found),
steps array vide via API. Vérifier :gh api repos/datagouv/apistration/environments/rubygems/deployment-branch-policies
Si une entrée est mal typée :gh api -X DELETE repos/datagouv/apistration/environments/rubygems/deployment-branch-policies/<id>
gh api -X POST repos/datagouv/apistration/environments/rubygems/deployment-branch-policies \
-f 'name=ruby-api-<gem>-v*' -f 'type=tag'
Puis gh run rerun <run-id>.
- Le run reste en
waiting tant que (1) le wait_timer (15 min) n'est pas
écoulé et (2) un reviewer de la liste rubygems n'a pas approuvé. Voir
gh api repos/datagouv/apistration/actions/runs/<id>/pending_deployments.
- Trusted publisher Workflow Filename qui ne matche pas :
No trusted publisher configured for this workflow found on https://rubygems.org.
Bug courant : entrée rubygems pointe sur un nom de workflow obsolète
(clients-ruby-release.yml) alors que le fichier réel est
clients-ruby.yml. Corriger sur rubygems, puis gh run rerun <id>.
rake aborted! sur release:source_control_push avec
error: src refspec refs/heads/HEAD does not match any : rubygems/release-gem@v1
checkout le tag (detached HEAD) puis lance bundle exec rake release,
ce qui chaîne release:source_control_push qui essaie un
git push origin HEAD impossible. Le Rakefile doit no-op cette tâche
quand CI=true (le tag est déjà sur origin, c'est lui qui a déclenché
la run).
- Re-trigger d'un workflow tag-based après fix : ne pas re-tagger en
vX.Y.Z+1. Force-déplacer le tag existant vers le nouveau merge commit :git tag -f ruby-api-<gem>-v<X.Y.Z> <new-merge-sha>
git push --force origin ruby-api-<gem>-v<X.Y.Z>
Le push tag ré-émet l'event GitHub et redéclenche le workflow. Tant que
la version n'a pas réellement été publiée sur rubygems, c'est légitime.
Étendre ce skill
Quand un nouveau langage rejoint clients/ (Node, Python, PHP, Java) :
ajouter une section ## Workflow (<langage>) ici avec :
- chemin du fichier de version (
package.json, pyproject.toml, etc.) ;
- format du tag attendu par le workflow CI correspondant ;
- registry cible (npm, PyPI, Packagist, Maven Central) ;
- éventuelles spécificités auth (OIDC, token secret, etc.).
Mettre à jour le description frontmatter pour citer le nouveau langage et
ses triggers.
1---2name: release-new-version3description: Release a new version of an official API Entreprise / API Particulier SDK to its package registry (rubygems for Ruby). Covers version bump, CHANGELOG update, release PR, tag conventions, and the OIDC-published workflow. Use when the user mentions "release", "publier", "publish sdk", "bump version sdk", "nouvelle version sdk", "rubygems", or asks to ship a new version of `api_entreprise` / `api_particulier` (Ruby today, more languages to come).4---56# Release a new SDK version78Source of truth for Ruby : [`clients/ruby/README.md`](../../../ruby/README.md)9§"Publier une version sur rubygems.org". Read it before deviating.1011## Scope1213One gem at a time. `api_entreprise` and `api_particulier` versionnent14indépendamment — ne jamais coupler les deux dans une même release.1516## Prérequis par gem (à valider au moins une fois)1718Ces points sont des **prérequis externes au repo**. Si l'un manque, le19workflow échoue de façon souvent silencieuse ou cryptique. Vérifier20**avant** de pousser un tag sur un gem qui n'a jamais été release via le21workflow.22231. **Trusted publisher OIDC sur rubygems** —24 `https://rubygems.org/profile/oidc/trusted_publishers` doit avoir une25 entrée pour le gem avec **exactement** :26 - GitHub Repository : `datagouv/apistration`27 - Workflow Filename : `clients-ruby.yml` (pas `clients-ruby-release.yml`,28 pas autre chose — doit matcher le nom de fichier sous29 `.github/workflows/`)30 - Environment : `rubygems`3132 Mismatch → erreur explicite à l'étape `configure-rubygems-credentials` :33 `No trusted publisher configured for this workflow found on34 https://rubygems.org for audience rubygems.org`.35362. **Branch policy de l'environment `rubygems`** typée `tag` (cf. Gotchas).37383. **Rakefile + `rake` dev dep** dans le gem39 (`clients/ruby/<gem>/Rakefile` + `gem 'rake'` dans le Gemfile group40 `:development`). Le Rakefile doit `require 'bundler/gem_tasks'` et,41 pour fonctionner avec `rubygems/release-gem@v1`, no-op42 `release:source_control_push` quand `CI=true` (cf. Rakefile en place).43 Sans Rakefile : `can't find executable rake for gem rake`.44454. **Premier release manuel** déjà effectué pour réserver le nom du gem46 sur rubygems (cf. `clients/ruby/README.md` §Prérequis).4748## Workflow (Ruby)49501. **Branche release dédiée**51 ```sh52 git checkout -b release/api-<entreprise|particulier>-<X.Y.Z>53 ```54552. **Bump** `clients/ruby/<gem>/lib/<gem>/version.rb`. SemVer :56 - patch : régénération scaffolding, changement OpenAPI rétro-compatible57 (paramètre devient optionnel, nouveau champ de réponse).58 - minor : nouvel endpoint, nouvelle méthode publique.59 - major : breaking change (paramètre requis ajouté, méthode supprimée,60 renommage).61623. **CHANGELOG** `clients/ruby/<gem>/CHANGELOG.md` — format Keep a Changelog :63 - Convertir `[Unreleased]` en `[X.Y.Z] - YYYY-MM-DD` quand la section64 contient le contenu releasé, sinon ajouter une nouvelle section65 `[X.Y.Z]` au-dessus de `[Unreleased]` (qui reste vide).66 - Sections : `Added` / `Changed` / `Deprecated` / `Removed` / `Fixed` /67 `Security`. Référencer le SHA upstream qui motive la release.68694. **Tests locaux**70 ```sh71 cd clients/ruby/<gem> && bundle exec rspec72 ```73 Le `Gemfile.lock` est modifié par le bundle (`<gem> (X.Y.Z)`) — l'inclure74 dans le commit.75765. **Commit unique**77 ```sh78 git commit -m "Release <gem> X.Y.Z"79 ```80 Message détaillé sur le pourquoi (changement upstream, breaking, etc.).81826. **PR vers `develop`** — review obligatoire, squash-merge.83847. **Tag le commit de merge sur `develop`** (pas la branche release jetable —85 sinon le tag pointe sur un commit orphelin) :86 ```sh87 git checkout develop && git pull88 git tag ruby-api-<entreprise|particulier>-v<X.Y.Z>89 git push origin ruby-api-<entreprise|particulier>-v<X.Y.Z>90 ```91928. **Workflow** `.github/workflows/clients-ruby.yml` se déclenche sur le tag :93 - vérifie `tag_version == gemspec.version` ;94 - relance rspec ;95 - publie via `rubygems/release-gem@v1` (OIDC trusted publisher, environment96 `rubygems`).9798 Surveiller la run, vérifier la version sur rubygems.org après succès.99100## Tags reconnus101102| Tag | Gem publié |103|---|---|104| `ruby-api-entreprise-v<X.Y.Z>` | `api_entreprise` |105| `ruby-api-particulier-v<X.Y.Z>` | `api_particulier` |106107Tag invalide → step "Resolve gem from tag" échoue et stoppe le workflow.108109## Gotchas110111- Tag mal placé (sur la branche release jetable non mergée) : le commit n'est112 atteignable depuis aucune branche permanente. Toujours tagger après merge,113 sur `develop`.114- Version dans `version.rb` ≠ tag : le job release échoue à115 "Verify tag version matches gemspec version".116- Ne jamais committer `Gemfile.lock` sans avoir bumpé `version.rb` avant —117 divergence silencieuse.118- Le `CHANGELOG.md` initial des gems publiait le contenu sous `[Unreleased]`119 alors que `0.1.0` était déjà sur rubygems. Au premier patch, convertir120 `[Unreleased]` → `[0.1.0]` puis ajouter `[0.1.1]` au-dessus.121- **Branch policy de l'environment `rubygems` doit être de type `tag`, pas122 `branch`.** Si la policy `ruby-api-<gem>-v*` est typée `branch` (cas123 rencontré sur `api_particulier` à la 0.1.1), GitHub rejette le déploiement124 instantanément : zéro step exécuté, log introuvable (`log not found`),125 steps array vide via API. Vérifier :126 ```sh127 gh api repos/datagouv/apistration/environments/rubygems/deployment-branch-policies128 ```129 Si une entrée est mal typée :130 ```sh131 gh api -X DELETE repos/datagouv/apistration/environments/rubygems/deployment-branch-policies/<id>132 gh api -X POST repos/datagouv/apistration/environments/rubygems/deployment-branch-policies \133 -f 'name=ruby-api-<gem>-v*' -f 'type=tag'134 ```135 Puis `gh run rerun <run-id>`.136- Le run reste en `waiting` tant que (1) le `wait_timer` (15 min) n'est pas137 écoulé et (2) un reviewer de la liste `rubygems` n'a pas approuvé. Voir138 `gh api repos/datagouv/apistration/actions/runs/<id>/pending_deployments`.139- **Trusted publisher Workflow Filename qui ne matche pas** : `No trusted140 publisher configured for this workflow found on https://rubygems.org`.141 Bug courant : entrée rubygems pointe sur un nom de workflow obsolète142 (`clients-ruby-release.yml`) alors que le fichier réel est143 `clients-ruby.yml`. Corriger sur rubygems, puis `gh run rerun <id>`.144- **`rake aborted!` sur `release:source_control_push`** avec145 `error: src refspec refs/heads/HEAD does not match any` : `rubygems/release-gem@v1`146 checkout le tag (detached HEAD) puis lance `bundle exec rake release`,147 ce qui chaîne `release:source_control_push` qui essaie un148 `git push origin HEAD` impossible. Le Rakefile doit no-op cette tâche149 quand `CI=true` (le tag est déjà sur origin, c'est lui qui a déclenché150 la run).151- **Re-trigger d'un workflow tag-based après fix** : ne pas re-tagger en152 `vX.Y.Z+1`. Force-déplacer le tag existant vers le nouveau merge commit :153 ```sh154 git tag -f ruby-api-<gem>-v<X.Y.Z> <new-merge-sha>155 git push --force origin ruby-api-<gem>-v<X.Y.Z>156 ```157 Le push tag ré-émet l'event GitHub et redéclenche le workflow. Tant que158 la version n'a pas réellement été publiée sur rubygems, c'est légitime.159160## Étendre ce skill161162Quand un nouveau langage rejoint `clients/` (Node, Python, PHP, Java) :163ajouter une section `## Workflow (<langage>)` ici avec :164- chemin du fichier de version (`package.json`, `pyproject.toml`, etc.) ;165- format du tag attendu par le workflow CI correspondant ;166- registry cible (npm, PyPI, Packagist, Maven Central) ;167- éventuelles spécificités auth (OIDC, token secret, etc.).168169Mettre à jour le `description` frontmatter pour citer le nouveau langage et170ses triggers.