From e092158fb0b6993a0c13ca60189b70d22083f953 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Apr 2026 11:41:50 +0000 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20bug:=20WOODPECKER=5FREPO=5FID=20not?= =?UTF-8?q?=20set=20in=20agent=20containers=20=E2=80=94=20ci-debug.sh=20fa?= =?UTF-8?q?ils=20to=20fetch=20logs,=20agents=20see=20"No=20logs=20availabl?= =?UTF-8?q?e"=20(#599)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/generators.sh | 54 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/lib/generators.sh b/lib/generators.sh index be487f8..6925d16 100644 --- a/lib/generators.sh +++ b/lib/generators.sh @@ -26,6 +26,46 @@ PROJECT_NAME="${PROJECT_NAME:-project}" # PRIMARY_BRANCH defaults to main (env.sh may have set it to 'master') PRIMARY_BRANCH="${PRIMARY_BRANCH:-main}" +# Helper: extract woodpecker_repo_id from a project TOML file +# Returns empty string if not found or file doesn't exist +_get_woodpecker_repo_id() { + local toml_file="$1" + if [ -f "$toml_file" ]; then + python3 -c " +import sys, tomllib +try: + with open(sys.argv[1], 'rb') as f: + cfg = tomllib.load(f) + ci = cfg.get('ci', {}) + wp_id = ci.get('woodpecker_repo_id', '0') + print(wp_id) +except: + print('0') +" "$toml_file" 2>/dev/null || echo "0" + else + echo "0" + fi +} + +# Find all project TOML files and extract the highest woodpecker_repo_id +# (used for the main agents service which doesn't have a per-project TOML) +_get_primary_woodpecker_repo_id() { + local projects_dir="${FACTORY_ROOT}/projects" + local max_id="0" + for toml in "${projects_dir}"/*.toml; do + [ -f "$toml" ] || continue + local repo_id + repo_id=$(_get_woodpecker_repo_id "$toml") + if [ -n "$repo_id" ] && [ "$repo_id" != "0" ]; then + # Use the first non-zero repo_id found (or highest if multiple) + if [ "$repo_id" -gt "$max_id" ] 2>/dev/null; then + max_id="$repo_id" + fi + fi + done + echo "$max_id" +} + # Parse project TOML for local-model agents and emit compose services. # Writes service definitions to stdout; caller handles insertion into compose file. _generate_local_model_services() { @@ -40,6 +80,10 @@ _generate_local_model_services() { for toml in "${projects_dir}"/*.toml; do [ -f "$toml" ] || continue + # Get woodpecker_repo_id for this project + local wp_repo_id + wp_repo_id=$(_get_woodpecker_repo_id "$toml") + # Parse [agents.*] sections using Python - output YAML-compatible format while IFS='=' read -r key value; do case "$key" in @@ -90,6 +134,7 @@ _generate_local_model_services() { DISINTO_CONTAINER: "1" PROJECT_REPO_ROOT: /home/agent/repos/${PROJECT_NAME:-project} WOODPECKER_DATA_DIR: /woodpecker-data + WOODPECKER_REPO_ID: "${wp_repo_id}" FORGE_BOT_USER_${service_name^^}: "${forge_user}" POLL_INTERVAL: "${poll_interval_val}" depends_on: @@ -186,7 +231,11 @@ _generate_compose_impl() { return 0 fi - cat > "$compose_file" <<'COMPOSEEOF' + # Extract primary woodpecker_repo_id from project TOML files + local wp_repo_id + wp_repo_id=$(_get_primary_woodpecker_repo_id) + + cat > "$compose_file" < Date: Fri, 10 Apr 2026 11:50:08 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20bug:=20WOODPECKER=5FREPO=5FID=20not?= =?UTF-8?q?=20set=20in=20agent=20containers=20=E2=80=94=20ci-debug.sh=20fa?= =?UTF-8?q?ils=20to=20fetch=20logs,=20agents=20see=20"No=20logs=20availabl?= =?UTF-8?q?e"=20(#599)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/generators.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/generators.sh b/lib/generators.sh index 6925d16..58c7dbf 100644 --- a/lib/generators.sh +++ b/lib/generators.sh @@ -39,7 +39,7 @@ try: ci = cfg.get('ci', {}) wp_id = ci.get('woodpecker_repo_id', '0') print(wp_id) -except: +except Exception: print('0') " "$toml_file" 2>/dev/null || echo "0" else @@ -235,7 +235,7 @@ _generate_compose_impl() { local wp_repo_id wp_repo_id=$(_get_primary_woodpecker_repo_id) - cat > "$compose_file" < "$compose_file" <<'COMPOSEEOF' # docker-compose.yml — generated by disinto init # Brings up Forgejo, Woodpecker, and the agent runtime. @@ -341,7 +341,7 @@ services: DISINTO_CONTAINER: "1" PROJECT_REPO_ROOT: /home/agent/repos/${PROJECT_NAME:-project} WOODPECKER_DATA_DIR: /woodpecker-data - WOODPECKER_REPO_ID: "${WP_REPO_ID:-}" + WOODPECKER_REPO_ID: "PLACEHOLDER_WP_REPO_ID" # IMPORTANT: agents get explicit environment variables (forge tokens, CI tokens, config). # Vault-only secrets (GITHUB_TOKEN, CLAWHUB_TOKEN, deploy keys) live in # .env.vault.enc and are NEVER injected here — only the runner @@ -438,12 +438,21 @@ volumes: networks: disinto-net: driver: bridge -COMPOSEEOF_VAR +COMPOSEEOF # Patch PROJECT_REPO_ROOT — interpolate PROJECT_NAME at generation time # (Docker Compose cannot resolve it; it's a shell variable, not a .env var) sed -i "s|\${PROJECT_NAME:-project}|${PROJECT_NAME}|g" "$compose_file" + # Patch WOODPECKER_REPO_ID — interpolate at generation time + # (Docker Compose cannot resolve it; it's a shell variable, not a .env var) + if [ -n "$wp_repo_id" ] && [ "$wp_repo_id" != "0" ]; then + sed -i "s|PLACEHOLDER_WP_REPO_ID|${wp_repo_id}|g" "$compose_file" + else + # Default to empty if no repo_id found (agents will handle gracefully) + sed -i "s|PLACEHOLDER_WP_REPO_ID||g" "$compose_file" + fi + # Patch the forgejo port mapping into the file if non-default if [ "$forge_port" != "3000" ]; then # Add port mapping to forgejo service so it's reachable from host during init