From ee5aad5f419447ad8aa506bb6499e4b2735fa533 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Wed, 14 Oct 2026 04:11:52 -0400 Subject: [PATCH] genome_pousser : la simulation dit ce que la poussee ferait, puis s'arrete En --check, la sonde de l'organisation (une lecture uri) etait sautee et la tache suivante echouait sur un statut absent, cache par no_log. La suite (colis, reception, poussee) est faite de command et d'ecritures que --check saute aussi : le verdict n'aurait rien prouve. Les deux sondes de la forge tournent desormais en simulation. En --check, le playbook lit la branche de la forge, la compare au poste (rev-list --left-right), nomme pour chaque depot ce que la poussee ferait, et s'arrete avant la premiere ecriture. Temoin : quatre cas nommes contre des clones jetables ; a jour partout contre les vrais depots, aux deux sites. CHANGELOG 150. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 18 +++++ playbooks/maintenance/genome_pousser.yml | 95 ++++++++++++++++++++++++ 2 files changed, 113 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58afe79..ea5cf45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 2026-10-14 (150) — La simulation de `genome-pousser` dit ce que la poussée ferait + +**95 preuves.** `make verifier` passe (site de Chezlepro), `make test` passe. Témoin : contre +des clones jetables (`-e genome_freres=…`), la simulation au site de TechnoLibre a nommé les +quatre cas — à jour, un commit en avance rapide, un commit de la forge absent du poste (le +runner refusera), un commit de la forge inconnu du poste. Contre les vrais dépôts, aux deux +sites : « à jour » partout, 0 changement. + +**`--check` échouait à la première lecture.** La sonde « l'organisation existe-t-elle ? » +(`uri`, une simple lecture) était sautée en simulation, et la tâche suivante tombait sur un +statut absent, en silence (`no_log`). Même réparée là, la suite n'aurait rien montré : colis, +réception et poussée sont des `command` ou des écritures `uri`, que `--check` saute, et le +verdict final aurait comparé une forge intacte à des colis jamais reçus. +- Les deux sondes de la forge tournent aussi en simulation (`check_mode: false`). +- En simulation, le playbook lit la branche que porte la forge, la compare au poste + (`git rev-list --count --left-right`), dit pour chaque dépôt ce que la poussée ferait, + puis s'arrête avant la première écriture. + ## 2026-10-14 (149) — Le second serveur de noms, sur l'autre site, par le tunnel **95 preuves.** `make verifier` passe (site de Chezlepro), `make test` passe. Témoin de bout en diff --git a/playbooks/maintenance/genome_pousser.yml b/playbooks/maintenance/genome_pousser.yml index f0d0b1b..bb172c0 100644 --- a/playbooks/maintenance/genome_pousser.yml +++ b/playbooks/maintenance/genome_pousser.yml @@ -22,6 +22,7 @@ # # make genome-pousser tous les depots portes par le runner # make genome-pousser DEPOT= un seul (le nom du depot sur la forge) +# make genome-pousser ARGS=--check ce que la poussee ferait, depot par depot, sans rien ecrire # # L'ECRITURE S'AUTHENTIFIE, LA LECTURE NON. `serveur_ops` clone en anonyme, par doctrine. # Pousser est un autre acte : le runner s'y presente avec SA cle — celle que `serveur_ops` @@ -123,6 +124,9 @@ url: "https://forge.{{ domaine_interne }}/api/v1/orgs/{{ serveur_ops_forge_organisation | default('genome') }}" validate_certs: false status_code: [200, 404] + # UNE LECTURE, DONC AUSSI EN SIMULATION : sans elle, `--check` sautait la sonde et la + # tache suivante echouait sur un statut absent (2026-10-14). + check_mode: false register: genome_org - name: Créer l'organisation du génome @@ -153,8 +157,99 @@ loop_control: label: "{{ item.depot }}" no_log: true + check_mode: false register: genome_depots_forge + # LA SIMULATION DIT CE QUE LA POUSSEE FERAIT, PUIS S'ARRETE (2026-10-14). + # + # Tout ce qui suit est `uri` en ecriture ou `command` : `--check` le saute, et le verdict + # final comparait alors une forge intacte a des colis jamais recus. On ne lit donc que la + # forge et le poste, on compare, et on rend la main avant la premiere ecriture. + - name: Simulation — la branche que porte la forge + ansible.builtin.uri: + url: >- + https://forge.{{ domaine_interne }}/api/v1/repos/{{ serveur_ops_forge_organisation + | default('genome') }}/{{ item.item.depot }}/branches/{{ item.item.branche | default('main') }} + url_username: forgejo-admin + url_password: "{{ vault_forgejo_admin }}" + force_basic_auth: true + validate_certs: false + status_code: [200, 404] + loop: "{{ genome_depots_forge.results }}" + loop_control: + label: "{{ item.item.depot }}" + register: genome_sim_forge + retries: 4 + delay: 3 + until: genome_sim_forge is succeeded + check_mode: false + no_log: true + when: + - ansible_check_mode + - item.status == 200 + + # `--left-right` : a gauche ce que la forge porte et que le poste n'a pas (le runner + # refusera, `--ff-only`), a droite ce qui serait pousse. rc 128 : le poste ne connait + # pas le commit de la forge — l'avance rapide est impossible a juger d'ici. + - name: Simulation — l'écart entre la forge et le poste + ansible.builtin.command: + argv: + - git + - -C + - "{{ genome_freres }}/{{ item.item.item.dest }}" + - rev-list + - --count + - --left-right + - "{{ item.json.commit.id }}...refs/heads/{{ item.item.item.branche | default('main') }}" + delegate_to: localhost + become: false + loop: "{{ genome_sim_forge.results }}" + loop_control: + label: "{{ item.item.item.depot }}" + register: genome_sim_ecart + check_mode: false + changed_when: false + failed_when: false + when: + - ansible_check_mode + - item.status | default(0) == 200 + + - name: Simulation — ce que la poussée ferait + vars: + genome_sim_lignes: >- + {%- set out = [] -%} + {%- if genome_org.status == 404 -%} + {%- set _ = out.append('organisation ' ~ (serveur_ops_forge_organisation | default('genome')) ~ ' : à créer') -%} + {%- endif -%} + {%- for r in genome_sim_ecart.results -%} + {%- set d = r.item.item.item.depot -%} + {%- if r.item.item.status == 404 -%} + {%- set _ = out.append(d ~ ' : dépôt à créer, puis tout poussé') -%} + {%- elif r.item.status | default(0) == 404 -%} + {%- set _ = out.append(d ~ ' : dépôt vide, tout poussé') -%} + {%- elif r.rc != 0 -%} + {%- set _ = out.append(d ~ ' : la forge porte ' ~ r.item.json.commit.id[:7] + ~ ', inconnu du poste — avance rapide impossible à juger d ici') -%} + {%- else -%} + {%- set lr = r.stdout.split() | map('int') | list -%} + {%- if lr[0] > 0 -%} + {%- set _ = out.append(d ~ ' : la forge a ' ~ lr[0] ~ ' commit(s) absent(s) du poste — le runner REFUSERA (--ff-only)') -%} + {%- elif lr[1] == 0 -%} + {%- set _ = out.append(d ~ ' : à jour (' ~ r.item.json.commit.id[:7] ~ ')') -%} + {%- else -%} + {%- set _ = out.append(d ~ ' : ' ~ r.item.json.commit.id[:7] ~ ' → ' ~ lr[1] ~ ' commit(s) en avance rapide') -%} + {%- endif -%} + {%- endif -%} + {%- endfor -%} + {{ out }} + ansible.builtin.debug: + msg: "{{ genome_sim_lignes }}" + when: ansible_check_mode + + - name: Simulation — s'arrêter avant la première écriture + ansible.builtin.meta: end_host + when: ansible_check_mode + - name: Créer les dépôts qui manquent ansible.builtin.uri: url: "https://forge.{{ domaine_interne }}/api/v1/orgs/{{ serveur_ops_forge_organisation | default('genome') }}/repos"