diff --git a/README.md b/README.md index e84396a..a1bd446 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Dépôt de pilotage par l'IA pour les projets : **équipe d'agents IA** dont le ## Usage (standalone) - **Racine d'exécution** : tous les scripts sont lancés depuis la **racine de ia_dev** (ce dépôt). L'id projet est résolu uniquement par **MAIL_TO** ou **AI_AGENT_TOKEN** (voir `projects/README.md`). -- **Config** : dans `projects//conf.json`, les champs `project_path`, `build_dirs`, `deploy.scripts_path`, `deploy.deploy_script_path`, `deploy.secrets_path`, `version.package_json_paths` sont des **chemins absolus** (vers les dépôts des projets). Les champs `mail.imap_bridge_env` et `git.token_file` sont **relatifs à la racine de ia_dev**. Le répertoire `.secrets` à la racine de ia_dev contient `token` et `gitea-issues/agent-loop.env`, `gitea-issues/imap-bridge.env`. +- **Config** : dans `projects//conf.json`, les chemins vers les dépôts projet peuvent être **absolus** ou **relatifs à la racine du monorepo smart_ide** lorsque ia_dev y est intégré (voir `lib/conf_path_resolve.sh`, `projects/README.md` amont). Les champs `mail.imap_bridge_env` et `git.token_file` sont **relatifs à la racine de ia_dev**. Le répertoire `.secrets` à la racine de ia_dev contient `token` et `gitea-issues/agent-loop.env`, `gitea-issues/imap-bridge.env`. Voir `projects/README.md` pour le schéma de configuration et les exemples. diff --git a/deploy/deploy-by-script-to.sh b/deploy/deploy-by-script-to.sh index 58a7c41..7e17d0e 100755 --- a/deploy/deploy-by-script-to.sh +++ b/deploy/deploy-by-script-to.sh @@ -29,6 +29,7 @@ if [[ -z "$PROJECT_ROOT" || ! -d "$PROJECT_ROOT" ]]; then fi if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "${PROJECT_CONFIG_PATH:-}" ]] && command -v jq >/dev/null 2>&1; then _sp="$(jq -r '.deploy.secrets_path // empty' "$PROJECT_CONFIG_PATH" 2>/dev/null)" + _sp="$(ia_dev_resolve_path_from_conf "$PROJECT_CONFIG_PATH" "$_sp")" if [[ -n "$_sp" && "$_sp" != "null" && -d "$_sp" ]]; then export SECRETS_BASE="$_sp" export LECOFFRE_SECRETS_BASE="$_sp" @@ -106,6 +107,7 @@ else deploy_script="$PROJECT_ROOT/deploy/scripts_v2/deploy.sh" if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "${PROJECT_CONFIG_PATH:-}" ]] && command -v jq >/dev/null 2>&1; then _cfg_script="$(jq -r '.deploy.deploy_script_path // ""' "$PROJECT_CONFIG_PATH" 2>/dev/null)" + _cfg_script="$(ia_dev_resolve_path_from_conf "$PROJECT_CONFIG_PATH" "$_cfg_script")" [[ -n "$_cfg_script" && -x "$_cfg_script" ]] && deploy_script="$_cfg_script" fi "$deploy_script" "$TARGET_BRANCH" diff --git a/deploy/lib/deploy-conf-handling.sh b/deploy/lib/deploy-conf-handling.sh index dcd95b7..5b826bb 100644 --- a/deploy/lib/deploy-conf-handling.sh +++ b/deploy/lib/deploy-conf-handling.sh @@ -3,6 +3,10 @@ # Add here any new deploy.* field that must be read the same way for all projects. # Do not put project-specific paths, hostnames, or phase ordering here beyond generic keys. +_DEPLOY_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=../../lib/conf_path_resolve.sh +source "${_DEPLOY_LIB_DIR}/../../lib/conf_path_resolve.sh" + # ia_dev_deploy_require_jq — exit 1 if jq missing (e.g. log_tag="[orchestrator]") ia_dev_deploy_require_jq() { local tag="${1:-[ia_dev][deploy]}" @@ -17,6 +21,7 @@ ia_dev_deploy_secrets_export_from_conf() { local conf="${1:?}" local secrets_path secrets_path="$(jq -r '.deploy.secrets_path // empty' "$conf")" + secrets_path="$(ia_dev_resolve_path_from_conf "$conf" "$secrets_path")" if [[ -n "$secrets_path" && "$secrets_path" != "null" && -d "$secrets_path" ]]; then export SECRETS_BASE="$secrets_path" export LECOFFRE_SECRETS_BASE="$secrets_path" diff --git a/deploy/orchestrator.sh b/deploy/orchestrator.sh index d529cda..244d383 100755 --- a/deploy/orchestrator.sh +++ b/deploy/orchestrator.sh @@ -52,6 +52,7 @@ ia_dev_deploy_export_runtime_context "$REPO_ROOT" "${1:-}" ia_dev_deploy_assert_handoff_context "$REPO_ROOT" "${1:-}" "${_ORCH_TAG}" DEPLOY_SCRIPT_PATH="$(jq -r '.deploy.deploy_script_path // empty' "$CONF")" +DEPLOY_SCRIPT_PATH="$(ia_dev_resolve_path_from_conf "$CONF" "$DEPLOY_SCRIPT_PATH")" PROJECT_ORCH_REL="$(jq -r '.deploy.project_orchestrator_path // empty' "$CONF")" if [[ -n "$PROJECT_ORCH_REL" && "$PROJECT_ORCH_REL" != "null" ]]; then diff --git a/deploy/pousse.sh b/deploy/pousse.sh index 9561155..5c76595 100755 --- a/deploy/pousse.sh +++ b/deploy/pousse.sh @@ -131,12 +131,16 @@ if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "$PROJECT_CONFIG_PATH" ]] && command - done < <(jq -r '.build_dirs[]? // empty' "$PROJECT_CONFIG_PATH" 2>/dev/null) fi if [[ ${#build_dirs[@]} -gt 0 ]]; then + # shellcheck source=../lib/conf_path_resolve.sh + source "${IA_DEV_ROOT}/lib/conf_path_resolve.sh" echo "[pousse] Build check (${#build_dirs[@]} dirs from project config)..." for dir in "${build_dirs[@]}"; do if [[ "$dir" = /* ]]; then abs_dir="$dir" + elif [[ "$dir" == ../* || "$dir" == ".." ]]; then + abs_dir="$(ia_dev_resolve_path_from_conf "$PROJECT_CONFIG_PATH" "$dir")" else - abs_dir="${repo_root}/${dir}" + abs_dir="${git_work_root}/${dir}" fi if [[ ! -d "$abs_dir" ]]; then echo "[pousse][WARN] Skipping build ${dir} (directory not found)" >&2 diff --git a/lib/conf_path_resolve.sh b/lib/conf_path_resolve.sh new file mode 100644 index 0000000..e8150f2 --- /dev/null +++ b/lib/conf_path_resolve.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Resolve paths in projects//conf.json: absolute paths unchanged; others relative to smart_ide monorepo root. +# Monorepo root is the directory that contains ./projects/ (conf at .../projects//conf.json) or, when the +# file lives under .../ia_dev/projects//conf.json, the parent of ./ia_dev/. + +# ia_dev_smart_ide_monorepo_root_from_conf +ia_dev_smart_ide_monorepo_root_from_conf() { + local conf="${1:?}" + local c="$conf" + if command -v realpath >/dev/null 2>&1; then + c="$(realpath "$conf" 2>/dev/null)" || c="$conf" + else + c="$(readlink -f "$conf" 2>/dev/null)" || c="$conf" + fi + local d + d="$(dirname "$c")" + if [[ "$c" == */ia_dev/projects/*/conf.json ]]; then + ( cd "$d/../../.." && pwd ) + return + fi + if [[ "$c" == */projects/*/conf.json ]]; then + ( cd "$d/../.." && pwd ) + return + fi + ( cd "$d/../.." && pwd ) +} + +# ia_dev_resolve_path_from_conf +ia_dev_resolve_path_from_conf() { + local conf="${1:?}" + local p="${2:-}" + p="${p//$'\r'/}" + if [[ -z "$p" || "$p" == "null" ]]; then + printf '%s\n' "" + return 0 + fi + if [[ "$p" = /* ]]; then + printf '%s\n' "$p" + return 0 + fi + local root + root="$(ia_dev_smart_ide_monorepo_root_from_conf "$conf")" + if ( cd "$root" && realpath -m "$p" >/dev/null 2>&1 ); then + ( cd "$root" && realpath -m "$p" ) + else + printf '%s\n' "$root/$p" + fi +} diff --git a/lib/project_git_root_from_conf.sh b/lib/project_git_root_from_conf.sh index f776014..3979ff9 100644 --- a/lib/project_git_root_from_conf.sh +++ b/lib/project_git_root_from_conf.sh @@ -7,9 +7,14 @@ # 2. deploy.git_work_tree (alias) # 3. dirname(deploy.secrets_path) — legacy; breaks if secrets live outside the repo tree # +# Paths may be absolute or relative to the smart_ide monorepo root (see conf_path_resolve.sh). +# # Preconditions: PROJECT_CONFIG_PATH set and jq available. # Sets: IA_PROJECT_GIT_ROOT (exported), or empty if unresolved. # +# shellcheck source=conf_path_resolve.sh +source "$(dirname "${BASH_SOURCE[0]}")/conf_path_resolve.sh" + ia_dev_resolve_project_git_root() { IA_PROJECT_GIT_ROOT="" export IA_PROJECT_GIT_ROOT @@ -19,18 +24,20 @@ ia_dev_resolve_project_git_root() { if ! command -v jq >/dev/null 2>&1; then return 0 fi - local r sp + local r sp r_abs sp_abs r="$(jq -r '.deploy.repository_root // .deploy.git_work_tree // empty' "$PROJECT_CONFIG_PATH" 2>/dev/null || true)" r="${r//$'\r'/}" - if [[ -n "$r" && "$r" != "null" && -d "$r" ]]; then - IA_PROJECT_GIT_ROOT="$r" + r_abs="$(ia_dev_resolve_path_from_conf "$PROJECT_CONFIG_PATH" "$r")" + if [[ -n "$r_abs" && -d "$r_abs" ]]; then + IA_PROJECT_GIT_ROOT="$r_abs" export IA_PROJECT_GIT_ROOT return 0 fi sp="$(jq -r '.deploy.secrets_path // empty' "$PROJECT_CONFIG_PATH" 2>/dev/null || true)" sp="${sp//$'\r'/}" - if [[ -n "$sp" && "$sp" != "null" ]]; then - IA_PROJECT_GIT_ROOT="$(dirname "$sp")" + sp_abs="$(ia_dev_resolve_path_from_conf "$PROJECT_CONFIG_PATH" "$sp")" + if [[ -n "$sp_abs" && "$sp_abs" != "null" ]]; then + IA_PROJECT_GIT_ROOT="$(dirname "$sp_abs")" export IA_PROJECT_GIT_ROOT fi } diff --git a/projects/README.md b/projects/README.md index d929ffc..9f84b90 100644 --- a/projects/README.md +++ b/projects/README.md @@ -5,7 +5,9 @@ This repo (`ia_dev`) is a **standalone** depot. Project-specific parameters are **Paths in conf.json:** The scripts in `deploy/` deploy and build the **configured projects** (lecoffreio, enso, algo, etc.) in their own directories; they do not deploy ia_dev. -- **Absolute** (required): `project_path`, `build_dirs`, `deploy.scripts_path`, `deploy.deploy_script_path`, `deploy.secrets_path`, `version.package_json_paths` — they point to each project repo. +- **Project / deploy paths** (`project_path`, `deploy.repository_root`, `deploy.deploy_script_path`, `deploy.secrets_path`, `deploy.scripts_path`): **absolute** or **relative to the smart_ide monorepo root** (parent of `projects/` and `ia_dev/`). Resolution uses `lib/conf_path_resolve.sh` when the config file lives under `…/projects//conf.json` or `…/ia_dev/projects//conf.json`. +- **`build_dirs`**: each entry is either **absolute**, **relative to the monorepo root** if it starts with `../`, or **relative to the project git root** (`repository_root`) otherwise (e.g. `enso/enso-front`). +- **`version.package_json_paths`**: **relative to the project git root** unless absolute (e.g. `package.json`, `enso/enso-front/package.json`). - **Relative to ia_dev root** (this project): `mail.imap_bridge_env`, `git.token_file`. They point to files under ia_dev’s own `.secrets/`. ## Current project selection @@ -23,7 +25,7 @@ The token in the request (e.g. Bearer) is matched by scanning all projects and a Scripts use **parameter** (or **`IA_PROJECT_ID`** env set by scripts), **`MAIL_TO`** (env) or **`AI_AGENT_TOKEN`** (env); they set `PROJECT_ID` and, for token, `PROJECT_ENV`. No other source (no `IA_PROJECT`, no `ai_project_id`, no `.ia_project`). -**Usage unique : standalone.** Tous les scripts sont lancés depuis la racine de ia_dev. Les chemins dans conf sont absolus (sauf `imap_bridge_env` et `token_file`, relatifs à la racine de ia_dev). +**Usage :** scripts lancés depuis la racine de ia_dev. Les chemins projet peuvent être absolus ou relatifs à la racine du monorepo **smart_ide** lorsque ia_dev y est intégré ; `mail.*` / `git.token_file` restent relatifs à la racine de ia_dev. ## Rule: conf.json is read-only for agents @@ -42,15 +44,15 @@ One JSON file per project: `projects//conf.json` (e.g. `projects/lecoffreio/ |-------|----------|-------------| | `id` | no | Project identifier (directory name under `projects/`); default: directory name. | | `name` | no | Human-readable project name. | -| `project_path` | no | **Absolute** path to the project deploy root (e.g. `/home/desk/code/lecoffre_ng_test/deploy`). | -| `build_dirs` | no | **Absolute** paths to directories where `npm run build` is run. | -| `deploy.scripts_path` | no | **Absolute** path to deploy scripts (e.g. `…/deploy/scripts_v2`). | -| `deploy.deploy_script_path` | no | **Absolute** path to deploy.sh (fallback / tooling; keep aligned with project orchestrator). | +| `project_path` | no | Git clone root for cron / tooling: **absolute** or **relative to smart_ide monorepo root** (e.g. `../enso`, `.`). | +| `build_dirs` | no | `npm run build` dirs: **absolute**; **monorepo-relative** if value starts with `../`; else **relative to repository root**. | +| `deploy.scripts_path` | no | Deploy scripts dir: **absolute** or **monorepo-relative** (e.g. `../enso/deploy/scripts_v2`). | +| `deploy.deploy_script_path` | no | **Absolute** or **monorepo-relative** path to `deploy.sh` (fallback / tooling). | | `deploy.project_orchestrator_path` | recommended | **Relative to `deploy.repository_root`** : single project orchestrator script (sequences project-specific deploy steps). Preferred over `deploy.hooks.phases`. | | `deploy.hooks.phases` | legacy | Optional list of scripts relative to `repository_root`; used only if `project_orchestrator_path` is unset. | -| `deploy.secrets_path` | no | **Absolute** path to the project’s `.secrets` directory. | +| `deploy.secrets_path` | no | **Absolute** or **monorepo-relative** path to the project’s `.secrets` directory. | | `deploy.host_stays_on_test` | no | If **true**, `deploy-by-script-to.sh` keeps the app clone on branch **test** for **pprod**/**prod** deploys (no `checkout`/`reset --hard` on those branches); the project’s `deploy.sh` aligns remotes / worktree. **false** or omitted: legacy behaviour (checkout target branch, sync, deploy, checkout **test**). LeCoffre sets **true** permanently in `projects/lecoffreio/conf.json`. | -| `version.package_json_paths` | no | **Absolute** paths to package.json files to bump. | +| `version.package_json_paths` | no | Paths to `package.json` for version bump: **absolute** or **relative to repository root**. | | `mail.imap_bridge_env` | no | **Relative to ia_dev root**: path to IMAP bridge env file (e.g. `.secrets/gitea-issues/imap-bridge.env`). | | `git.token_file` | no | **Relative to ia_dev root**: path to Gitea token file (e.g. `.secrets/gitea-issues/token`). | diff --git a/projects/enso/conf.json b/projects/enso/conf.json index 1835564..6f0e485 100644 --- a/projects/enso/conf.json +++ b/projects/enso/conf.json @@ -1,23 +1,25 @@ { "id": "enso", "name": "enso", - "project_path": "/home/desk/code/enso/deploy", + "cron": { + "git_pull": true + }, + "project_path": "../enso", "build_dirs": [ - "/home/desk/code/enso/deploy/lecoffre-ressources-dev", - "/home/desk/code/enso/deploy/lecoffre-back-main", - "/home/desk/code/enso/deploy/lecoffre-front-main" + ".", + "enso/enso-front" ], "deploy": { - "repository_root": "/home/desk/code/enso", - "scripts_path": "/home/desk/code/enso/deploy/scripts_v2", - "deploy_script_path": "/home/desk/code/enso/deploy/scripts_v2/deploy.sh", + "repository_root": "../enso", + "scripts_path": "../enso/deploy/scripts_v2", + "deploy_script_path": "../enso/deploy/scripts_v2/deploy.sh", "project_orchestrator_path": "deploy/scripts_v2/deploy.sh", - "secrets_path": "/home/desk/code/enso/.secrets" + "secrets_path": "../enso/.secrets" }, "version": { "package_json_paths": [ - "/home/desk/code/enso/deploy/lecoffre-back-main/package.json", - "/home/desk/code/enso/deploy/lecoffre-front-main/package.json" + "package.json", + "enso/enso-front/package.json" ], "splash_app_name": "enso" }, @@ -25,11 +27,11 @@ "imap_bridge_env": ".secrets/gitea-issues/imap-bridge.env" }, "git": { - "wiki_url": "https://git.4nkweb.com/nicolas.cantu/enso/wiki", + "wiki_url": "https://git.4nkweb.com/4nk/enso/wiki", "token_file": ".secrets/gitea-issues/token" }, "tickets": { - "ticketing_url": "https://git.4nkweb.com/nicolas.cantu/enso/issues", + "ticketing_url": "https://git.4nkweb.com/4nk/enso/issues", "authorized_emails": { "to": [ { @@ -40,5 +42,43 @@ ], "from": ["nicolas.4nk@pm.me"] } + }, + "smart_ide": { + "remote_data_access": { + "environments": { + "test": { + "ssh_host_alias": "enso-test-app", + "remote_data_directories": [ + { + "role": "docv_storage", + "path_on_server": "/var/lib/enso/test/data" + } + ] + }, + "pprod": { + "ssh_host_alias": "enso-pprod-app", + "remote_data_directories": [ + { + "role": "docv_storage", + "path_on_server": "/var/lib/enso/pprod/data" + } + ] + }, + "prod": { + "ssh_host_alias": "enso-prod-app", + "remote_data_directories": [ + { + "role": "docv_storage", + "path_on_server": "/var/lib/enso/prod/data" + } + ] + } + } + }, + "anythingllm_workspace_slug": { + "test": "enso-test", + "pprod": "enso-pprod", + "prod": "enso-prod" + } } } diff --git a/projects/smart_ide/conf.json b/projects/smart_ide/conf.json index d29cb0e..1e7567a 100644 --- a/projects/smart_ide/conf.json +++ b/projects/smart_ide/conf.json @@ -1,7 +1,10 @@ { "id": "smart_ide", "name": "smart_ide", - "project_path": "/home/ncantu/code/smart_ide", + "cron": { + "git_pull": true + }, + "project_path": ".", "build_dirs": [], "deploy": {}, "version": { @@ -27,5 +30,23 @@ ], "from": ["nicolas.4nk@pm.me"] } + }, + "smart_ide": { + "remote_data_access": { + "environments": { + "test": { + "ssh_host_alias": "smart-ide-test", + "remote_data_directories": [] + }, + "pprod": { + "ssh_host_alias": "smart-ide-pprod", + "remote_data_directories": [] + }, + "prod": { + "ssh_host_alias": "smart-ide-prod", + "remote_data_directories": [] + } + } + } } }