diff --git a/ansible/arcodange/factory/roles/ci_base_image/defaults/main.yml b/ansible/arcodange/factory/roles/ci_base_image/defaults/main.yml index e242e9a..9f88843 100644 --- a/ansible/arcodange/factory/roles/ci_base_image/defaults/main.yml +++ b/ansible/arcodange/factory/roles/ci_base_image/defaults/main.yml @@ -48,5 +48,15 @@ ci_base_image_node_major: 20 # images de runner elles-mêmes. ci_base_image_pin: true -# Reconstruire même si l'image existe déjà (utile après un changement de version). +# Où le contexte de build est déposé SUR LA MACHINE CIBLE. `docker_image_build` +# s'exécute sur la cible : son `path:` est un chemin de la cible, jamais du +# contrôleur. (Première version : `{{ role_path }}/files/` → le playbook mourait +# sur « is not an existing directory », sur les deux hôtes.) +ci_base_image_contexte: /tmp/ci-base-image + +# Reconstruire même si l'image existe déjà. ⚠ Inutile pour un simple changement +# du Dockerfile : le rôle le détecte et reconstruit tout seul (voir tasks/). +# Ce drapeau sert aux cas que le Dockerfile ne montre pas — une montée de +# `bun.lock` côté kadans, par exemple, qui change les VERSIONS attendues sans +# changer le fichier. ci_base_image_force_rebuild: false diff --git a/ansible/arcodange/factory/roles/ci_base_image/tasks/main.yml b/ansible/arcodange/factory/roles/ci_base_image/tasks/main.yml index 5ac76f2..f1ab121 100644 --- a/ansible/arcodange/factory/roles/ci_base_image/tasks/main.yml +++ b/ansible/arcodange/factory/roles/ci_base_image/tasks/main.yml @@ -6,12 +6,45 @@ # atterrit sur une machine sans l'image échouerait AVANT sa première étape — # `runs-on`/`container:` est résolu par le runner, pas par le workflow. +# ══════════════════════════════════════════════════════════════════════════ +# ⚠ LE CONTEXTE DE BUILD DOIT ÊTRE SUR LA MACHINE, PAS SUR LE CONTRÔLEUR. +# +# `docker_image_build` s'exécute SUR LA CIBLE : son `path:` est un chemin de la +# cible. La première version passait `{{ role_path }}/files/` — un chemin du +# CONTRÔLEUR — et le playbook mourait sur les deux hôtes : +# +# "/Users/…/roles/ci_base_image/files/" is not an existing directory +# +# Le motif venait du rôle `playwright`, qui l'utilise LÉGITIMEMENT parce qu'il +# construit en local ; recopié tel quel pour un build distant, il ne peut pas +# marcher. On copie donc le contexte d'abord. +# ══════════════════════════════════════════════════════════════════════════ +- name: Créer le répertoire de contexte de build sur la machine + ansible.builtin.file: + path: '{{ ci_base_image_contexte }}' + state: directory + mode: '0755' + +- name: Déposer le Dockerfile sur la machine + ansible.builtin.copy: + src: Dockerfile + dest: '{{ ci_base_image_contexte }}/Dockerfile' + mode: '0644' + register: ci_base_image_dockerfile + - name: Construire {{ ci_base_image_name }}:{{ ci_base_image_tag }} community.docker.docker_image_build: name: '{{ ci_base_image_name }}' tag: '{{ ci_base_image_tag }}' - path: '{{ role_path }}/files/' - rebuild: '{{ "always" if ci_base_image_force_rebuild else "never" }}' + path: '{{ ci_base_image_contexte }}' + # RECONSTRUCTION CONDITIONNELLE : `never` en régime normal (le playbook ne + # rebâtit pas 3,3 Go à chaque passage), mais `always` dès que le Dockerfile + # a CHANGÉ sur la machine — c'est ce qui rend l'ajout d'une bibliothèque + # effectif sans avoir à penser à un drapeau. + rebuild: >- + {{ "always" + if (ci_base_image_force_rebuild or ci_base_image_dockerfile is changed) + else "never" }} args: CI_BASE_FROM: '{{ ci_base_image_from }}' NODE_MAJOR: '{{ ci_base_image_node_major }}'