Compare commits
10 Commits
chore/add-
...
chore/depl
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b612214bb | |||
| 29a6c349aa | |||
|
|
33a227c401 | ||
| 396ad4df7c | |||
|
|
0b39427090 | ||
| 8fcb18cb46 | |||
| d03fc519de | |||
| 97dd3797d6 | |||
| 6c7b7ab6a0 | |||
| 105dfe1b5b |
@@ -44,8 +44,8 @@ jobs:
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
|
|
||||||
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON, "utf8"));
|
||||||
|
|
||||||
const repoObj = ev?.repository || {};
|
const repoObj = ev?.repository || {};
|
||||||
|
|
||||||
const cloneUrl =
|
const cloneUrl =
|
||||||
repoObj?.clone_url ||
|
repoObj?.clone_url ||
|
||||||
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
(repoObj?.html_url ? (repoObj.html_url.replace(/\/$/,"") + ".git") : "");
|
||||||
@@ -112,7 +112,7 @@ jobs:
|
|||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
if [[ "$LABEL_NAME" != "state/approved" && "$LABEL_NAME" != "workflow_dispatch" ]]; then
|
if [[ "$LABEL_NAME" != "state/approved" && "$LABEL_NAME" != "workflow_dispatch" ]]; then
|
||||||
echo "ℹ️ label=$LABEL_NAME => skip"
|
echo "ℹ️ label=$LABEL_NAME => skip"
|
||||||
echo 'SKIP=1' >> /tmp/anno.env
|
echo "SKIP=1" >> /tmp/anno.env
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
echo "✅ proceed (issue=$ISSUE_NUMBER)"
|
echo "✅ proceed (issue=$ISSUE_NUMBER)"
|
||||||
@@ -128,6 +128,7 @@ jobs:
|
|||||||
git remote add origin "$CLONE_URL"
|
git remote add origin "$CLONE_URL"
|
||||||
git fetch --depth 1 origin "$DEFAULT_BRANCH"
|
git fetch --depth 1 origin "$DEFAULT_BRANCH"
|
||||||
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
||||||
|
git log -1 --oneline
|
||||||
|
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: |
|
run: |
|
||||||
@@ -136,7 +137,34 @@ jobs:
|
|||||||
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
npm ci
|
npm ci
|
||||||
|
|
||||||
|
- name: Check apply script exists
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
source /tmp/anno.env
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
|
test -f scripts/apply-annotation-ticket.mjs || {
|
||||||
|
echo "❌ missing scripts/apply-annotation-ticket.mjs on $DEFAULT_BRANCH"
|
||||||
|
ls -la scripts | sed -n '1,200p' || true
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Build dist (needed for --verify)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
source /tmp/anno.env
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
|
|
||||||
|
npm run build:clean
|
||||||
|
|
||||||
|
test -f dist/para-index.json || {
|
||||||
|
echo "❌ missing dist/para-index.json after build"
|
||||||
|
ls -la dist | sed -n '1,200p' || true
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo "✅ dist/para-index.json present"
|
||||||
|
|
||||||
- name: Apply ticket on bot branch (strict+verify, commit)
|
- name: Apply ticket on bot branch (strict+verify, commit)
|
||||||
|
continue-on-error: true
|
||||||
env:
|
env:
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
BOT_GIT_NAME: ${{ secrets.BOT_GIT_NAME }}
|
BOT_GIT_NAME: ${{ secrets.BOT_GIT_NAME }}
|
||||||
@@ -145,6 +173,7 @@ jobs:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
|
|
||||||
test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; }
|
test -n "${FORGE_TOKEN:-}" || { echo "❌ Missing secret FORGE_TOKEN"; exit 1; }
|
||||||
|
|
||||||
git config user.name "${BOT_GIT_NAME:-archicratie-bot}"
|
git config user.name "${BOT_GIT_NAME:-archicratie-bot}"
|
||||||
@@ -166,12 +195,16 @@ jobs:
|
|||||||
RC=$?
|
RC=$?
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
tail -n 160 "$LOG" || true
|
echo "APPLY_RC=$RC" >> /tmp/anno.env
|
||||||
|
|
||||||
|
echo "== apply log (tail) =="
|
||||||
|
tail -n 180 "$LOG" || true
|
||||||
|
|
||||||
END_SHA="$(git rev-parse HEAD)"
|
END_SHA="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
if [[ "$RC" -ne 0 ]]; then
|
if [[ "$RC" -ne 0 ]]; then
|
||||||
echo "APPLY_RC=$RC" >> /tmp/anno.env
|
echo "NOOP=0" >> /tmp/anno.env
|
||||||
exit "$RC"
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$START_SHA" == "$END_SHA" ]]; then
|
if [[ "$START_SHA" == "$END_SHA" ]]; then
|
||||||
@@ -181,13 +214,42 @@ jobs:
|
|||||||
echo "END_SHA=$END_SHA" >> /tmp/anno.env
|
echo "END_SHA=$END_SHA" >> /tmp/anno.env
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Comment issue on failure (strict/verify/etc)
|
||||||
|
if: ${{ always() }}
|
||||||
|
env:
|
||||||
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
source /tmp/anno.env
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
|
|
||||||
|
RC="${APPLY_RC:-0}"
|
||||||
|
if [[ "$RC" == "0" ]]; then
|
||||||
|
echo "ℹ️ no failure detected"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
BODY="$(tail -n 160 /tmp/apply.log | sed 's/\r$//')"
|
||||||
|
MSG="❌ apply-annotation-ticket a échoué (rc=${RC}).\n\n\`\`\`\n${BODY}\n\`\`\`\n"
|
||||||
|
|
||||||
|
PAYLOAD="$(node --input-type=module -e 'console.log(JSON.stringify({body: process.argv[1]||""}))' "$MSG")"
|
||||||
|
|
||||||
|
curl -fsS -X POST \
|
||||||
|
-H "Authorization: token $FORGE_TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
||||||
|
--data-binary "$PAYLOAD"
|
||||||
|
|
||||||
- name: Comment issue if no-op (already applied)
|
- name: Comment issue if no-op (already applied)
|
||||||
|
if: ${{ always() }}
|
||||||
env:
|
env:
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||||
|
|
||||||
|
[[ "${APPLY_RC:-0}" == "0" ]] || exit 0
|
||||||
[[ "${NOOP:-0}" == "1" ]] || exit 0
|
[[ "${NOOP:-0}" == "1" ]] || exit 0
|
||||||
|
|
||||||
MSG="ℹ️ Ticket #${ISSUE_NUMBER} : rien à appliquer (déjà présent / dédupliqué)."
|
MSG="ℹ️ Ticket #${ISSUE_NUMBER} : rien à appliquer (déjà présent / dédupliqué)."
|
||||||
@@ -200,12 +262,15 @@ jobs:
|
|||||||
--data-binary "$PAYLOAD"
|
--data-binary "$PAYLOAD"
|
||||||
|
|
||||||
- name: Push bot branch
|
- name: Push bot branch
|
||||||
|
if: ${{ always() }}
|
||||||
env:
|
env:
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||||
|
|
||||||
|
[[ "${APPLY_RC:-0}" == "0" ]] || { echo "ℹ️ apply failed -> skip push"; exit 0; }
|
||||||
[[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip push"; exit 0; }
|
[[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip push"; exit 0; }
|
||||||
|
|
||||||
AUTH_URL="$(node --input-type=module -e '
|
AUTH_URL="$(node --input-type=module -e '
|
||||||
@@ -220,12 +285,15 @@ jobs:
|
|||||||
git push -u origin "$BRANCH"
|
git push -u origin "$BRANCH"
|
||||||
|
|
||||||
- name: Create PR + comment issue
|
- name: Create PR + comment issue
|
||||||
|
if: ${{ always() }}
|
||||||
env:
|
env:
|
||||||
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
FORGE_TOKEN: ${{ secrets.FORGE_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
source /tmp/anno.env
|
source /tmp/anno.env
|
||||||
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
[[ "${SKIP:-0}" != "1" ]] || exit 0
|
||||||
|
|
||||||
|
[[ "${APPLY_RC:-0}" == "0" ]] || { echo "ℹ️ apply failed -> skip PR"; exit 0; }
|
||||||
[[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip PR"; exit 0; }
|
[[ "${NOOP:-0}" == "0" ]] || { echo "ℹ️ no-op -> skip PR"; exit 0; }
|
||||||
|
|
||||||
PR_TITLE="anno: apply ticket #${ISSUE_NUMBER}"
|
PR_TITLE="anno: apply ticket #${ISSUE_NUMBER}"
|
||||||
@@ -257,3 +325,19 @@ jobs:
|
|||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
"$API_BASE/api/v1/repos/$OWNER/$REPO/issues/$ISSUE_NUMBER/comments" \
|
||||||
--data-binary "$C_PAYLOAD"
|
--data-binary "$C_PAYLOAD"
|
||||||
|
|
||||||
|
echo "✅ PR: $PR_URL"
|
||||||
|
|
||||||
|
- name: Finalize (fail job if apply failed)
|
||||||
|
if: ${{ always() }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
source /tmp/anno.env || true
|
||||||
|
[[ "${SKIP:-0}" != "1" ]] || { echo "ℹ️ skipped"; exit 0; }
|
||||||
|
|
||||||
|
RC="${APPLY_RC:-0}"
|
||||||
|
if [[ "$RC" != "0" ]]; then
|
||||||
|
echo "❌ apply failed (rc=$RC)"
|
||||||
|
exit "$RC"
|
||||||
|
fi
|
||||||
|
echo "✅ apply ok"
|
||||||
223
.gitea/workflows/deploy-staging-live.yml
Normal file
223
.gitea/workflows/deploy-staging-live.yml
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
name: Deploy (staging + live) — annotations
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
# valeurs "publiques" injectées au build (import.meta.env.PUBLIC_*)
|
||||||
|
PUBLIC_GITEA_BASE: https://gitea.archicratie.trans-hands.synology.me
|
||||||
|
PUBLIC_GITEA_OWNER: Archicratia
|
||||||
|
PUBLIC_GITEA_REPO: archicratie-edition
|
||||||
|
|
||||||
|
# canonical/sitemap (IMPORTANT)
|
||||||
|
STAGING_PUBLIC_SITE: https://staging.archicratie.trans-hands.synology.me
|
||||||
|
LIVE_PUBLIC_SITE: https://archicratie.trans-hands.synology.me
|
||||||
|
|
||||||
|
REQUIRE_PUBLIC_SITE: "1"
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: mcr.microsoft.com/devcontainers/javascript-node:22-bookworm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Tools sanity + install docker cli
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
git --version
|
||||||
|
node --version
|
||||||
|
npm --version
|
||||||
|
|
||||||
|
# docker cli + compose plugin + curl (dans le conteneur du job)
|
||||||
|
apt-get update -y
|
||||||
|
apt-get install -y --no-install-recommends docker.io docker-compose-plugin curl ca-certificates
|
||||||
|
docker --version
|
||||||
|
docker compose version
|
||||||
|
curl --version | head -n 1
|
||||||
|
|
||||||
|
- name: Checkout (from event.json, no external actions)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
export EVENT_JSON="/var/run/act/workflow/event.json"
|
||||||
|
test -f "$EVENT_JSON" || { echo "❌ Missing $EVENT_JSON"; exit 1; }
|
||||||
|
|
||||||
|
eval "$(node --input-type=module -e 'import fs from "node:fs";
|
||||||
|
const ev = JSON.parse(fs.readFileSync(process.env.EVENT_JSON,"utf8"));
|
||||||
|
const repo =
|
||||||
|
ev?.repository?.clone_url ||
|
||||||
|
(ev?.repository?.html_url ? (ev.repository.html_url.replace(/\/$/,"") + ".git") : "");
|
||||||
|
const after =
|
||||||
|
ev?.after ||
|
||||||
|
ev?.pull_request?.head?.sha ||
|
||||||
|
ev?.head_commit?.id ||
|
||||||
|
ev?.sha || "";
|
||||||
|
const before =
|
||||||
|
ev?.before || "";
|
||||||
|
if (!repo) throw new Error("No repository url in event.json");
|
||||||
|
if (!after) throw new Error("No after sha in event.json");
|
||||||
|
process.stdout.write(`REPO_URL=${JSON.stringify(repo)}\nAFTER=${JSON.stringify(after)}\nBEFORE=${JSON.stringify(before)}\n`);
|
||||||
|
')"
|
||||||
|
|
||||||
|
echo "Repo URL: $REPO_URL"
|
||||||
|
echo "BEFORE: $BEFORE"
|
||||||
|
echo "AFTER: $AFTER"
|
||||||
|
|
||||||
|
rm -rf .git
|
||||||
|
git init -q
|
||||||
|
git remote add origin "$REPO_URL"
|
||||||
|
|
||||||
|
# fetch AFTER (+ BEFORE si dispo)
|
||||||
|
git fetch --depth 50 origin "$AFTER"
|
||||||
|
git -c advice.detachedHead=false checkout -q FETCH_HEAD
|
||||||
|
|
||||||
|
# fetch BEFORE si c'est un sha plausible (pas 0000..)
|
||||||
|
if [[ -n "$BEFORE" && ! "$BEFORE" =~ ^0+$ ]]; then
|
||||||
|
git fetch --depth 50 origin "$BEFORE" || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
git log -1 --oneline
|
||||||
|
|
||||||
|
- name: Gate — auto deploy only on annotations/media changes
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# récupère BEFORE/AFTER depuis event.json (déjà dispo dans env du shell précédent? non)
|
||||||
|
export EVENT_JSON="/var/run/act/workflow/event.json"
|
||||||
|
BEFORE="$(node --input-type=module -e 'import fs from "node:fs"; const ev=JSON.parse(fs.readFileSync(process.env.EVENT_JSON,"utf8")); process.stdout.write(String(ev?.before||""))')"
|
||||||
|
AFTER="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
|
echo "AFTER=$AFTER"
|
||||||
|
echo "BEFORE=$BEFORE"
|
||||||
|
|
||||||
|
# si BEFORE absent/zeros → on autorise (premier push / edge case)
|
||||||
|
if [[ -z "$BEFORE" || "$BEFORE" =~ ^0+$ ]]; then
|
||||||
|
echo "ℹ️ No BEFORE sha => allow deploy"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# liste des fichiers changés
|
||||||
|
CHANGED="$(git diff --name-only "$BEFORE" "$AFTER" || true)"
|
||||||
|
echo "== changed files =="
|
||||||
|
echo "$CHANGED" | sed -n '1,240p'
|
||||||
|
|
||||||
|
# autorisé uniquement sur ces chemins
|
||||||
|
BAD=0
|
||||||
|
while IFS= read -r f; do
|
||||||
|
[[ -z "$f" ]] && continue
|
||||||
|
if [[ "$f" =~ ^src/annotations/ ]] || [[ "$f" =~ ^public/media/ ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# tout le reste => on skip l’auto-deploy (pas un échec)
|
||||||
|
echo "⚠️ non-annotation change detected: $f"
|
||||||
|
BAD=1
|
||||||
|
done <<< "$CHANGED"
|
||||||
|
|
||||||
|
if [[ "$BAD" -eq 1 ]]; then
|
||||||
|
echo "ℹ️ Skip auto deploy (changes not limited to annotations/media)."
|
||||||
|
echo "SKIP_DEPLOY=1" >> "$GITHUB_ENV" 2>/dev/null || true
|
||||||
|
echo "SKIP_DEPLOY=1" >> /tmp/deploy.env
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Allowed: annotations/media only"
|
||||||
|
|
||||||
|
- name: Build + deploy staging (blue) then smoke
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [[ -f /tmp/deploy.env ]] && grep -q '^SKIP_DEPLOY=1' /tmp/deploy.env; then
|
||||||
|
echo "ℹ️ skipped"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
TS="$(date -u +%Y%m%d-%H%M%S)"
|
||||||
|
echo "TS=$TS"
|
||||||
|
|
||||||
|
# backup image tag (best effort)
|
||||||
|
docker image inspect archicratie-web:blue >/dev/null 2>&1 && \
|
||||||
|
docker image tag archicratie-web:blue "archicratie-web:blue.BAK.${TS}" || true
|
||||||
|
|
||||||
|
# IMPORTANT: forcer les args de build (staging)
|
||||||
|
export PUBLIC_SITE="$STAGING_PUBLIC_SITE"
|
||||||
|
|
||||||
|
# on évite les conflits de "container name already in use"
|
||||||
|
docker rm -f archicratie-web-blue >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
docker compose -f docker-compose.yml build web_blue
|
||||||
|
docker compose -f docker-compose.yml up -d --force-recreate web_blue
|
||||||
|
|
||||||
|
# smoke staging (8081)
|
||||||
|
echo "== smoke staging (8081) =="
|
||||||
|
curl -fsS -o /dev/null "http://127.0.0.1:8081/para-index.json"
|
||||||
|
curl -fsS -o /dev/null "http://127.0.0.1:8081/annotations-index.json"
|
||||||
|
CANON="$(curl -fsS "http://127.0.0.1:8081/archicrat-ia/chapitre-1/" | grep -oE 'rel="canonical" href="[^"]+"' | head -n1 || true)"
|
||||||
|
echo "canonical: $CANON"
|
||||||
|
echo "$CANON" | grep -q "$STAGING_PUBLIC_SITE" || { echo "❌ staging canonical mismatch"; exit 1; }
|
||||||
|
echo "✅ staging OK"
|
||||||
|
|
||||||
|
- name: Build + deploy live (green) then smoke + rollback if needed
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
if [[ -f /tmp/deploy.env ]] && grep -q '^SKIP_DEPLOY=1' /tmp/deploy.env; then
|
||||||
|
echo "ℹ️ skipped"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
TS="$(date -u +%Y%m%d-%H%M%S)"
|
||||||
|
echo "TS=$TS"
|
||||||
|
|
||||||
|
# backup image tag (best effort)
|
||||||
|
docker image inspect archicratie-web:green >/dev/null 2>&1 && \
|
||||||
|
docker image tag archicratie-web:green "archicratie-web:green.BAK.${TS}" || true
|
||||||
|
|
||||||
|
# IMPORTANT: args de build (live)
|
||||||
|
export PUBLIC_SITE="$LIVE_PUBLIC_SITE"
|
||||||
|
|
||||||
|
# on évite les conflits
|
||||||
|
docker rm -f archicratie-web-green >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# build + up
|
||||||
|
set +e
|
||||||
|
docker compose -f docker-compose.yml build web_green
|
||||||
|
BUILD_RC=$?
|
||||||
|
set -e
|
||||||
|
[[ "$BUILD_RC" -eq 0 ]] || { echo "❌ build live failed"; exit 1; }
|
||||||
|
|
||||||
|
docker compose -f docker-compose.yml up -d --force-recreate web_green
|
||||||
|
|
||||||
|
# smoke live (8082)
|
||||||
|
echo "== smoke live (8082) =="
|
||||||
|
set +e
|
||||||
|
curl -fsS -o /dev/null "http://127.0.0.1:8082/para-index.json"
|
||||||
|
A1=$?
|
||||||
|
curl -fsS -o /dev/null "http://127.0.0.1:8082/annotations-index.json"
|
||||||
|
A2=$?
|
||||||
|
CANON="$(curl -fsS "http://127.0.0.1:8082/archicrat-ia/chapitre-1/" | grep -oE 'rel="canonical" href="[^"]+"' | head -n1 || true)"
|
||||||
|
echo "canonical: $CANON"
|
||||||
|
echo "$CANON" | grep -q "$LIVE_PUBLIC_SITE"
|
||||||
|
A3=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ "$A1" -ne 0 || "$A2" -ne 0 || "$A3" -ne 0 ]]; then
|
||||||
|
echo "❌ live smoke failed => rollback"
|
||||||
|
|
||||||
|
# rollback image tag if backup exists
|
||||||
|
if docker image inspect "archicratie-web:green.BAK.${TS}" >/dev/null 2>&1; then
|
||||||
|
docker image tag "archicratie-web:green.BAK.${TS}" archicratie-web:green
|
||||||
|
docker rm -f archicratie-web-green >/dev/null 2>&1 || true
|
||||||
|
docker compose -f docker-compose.yml up -d --force-recreate --no-build web_green
|
||||||
|
echo "✅ rollback applied"
|
||||||
|
else
|
||||||
|
echo "⚠️ no backup image tag found => cannot rollback automatically"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ live OK"
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 822 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 822 KiB |
21
src/annotations/archicrat-ia/chapitre-4.yml
Normal file
21
src/annotations/archicrat-ia/chapitre-4.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
schema: 1
|
||||||
|
page: archicrat-ia/chapitre-4
|
||||||
|
paras:
|
||||||
|
p-2-31b12529:
|
||||||
|
media:
|
||||||
|
- type: image
|
||||||
|
src: /media/archicrat-ia/chapitre-4/p-2-31b12529/Capture_d_e_cran_2026-02-16_a_13.05.58.png
|
||||||
|
caption: "[Media] p-2-31b12529 — Chapitre 4 — Histoire archicratique des
|
||||||
|
révolutions industrielles"
|
||||||
|
credit: ""
|
||||||
|
ts: 2026-02-25T18:58:32.359Z
|
||||||
|
fromIssue: 115
|
||||||
|
p-7-1da4a458:
|
||||||
|
media:
|
||||||
|
- type: image
|
||||||
|
src: /media/archicrat-ia/chapitre-4/p-7-1da4a458/Capture_d_e_cran_2026-02-16_a_13.05.58.png
|
||||||
|
caption: "[Media] p-7-1da4a458 — Chapitre 4 — Histoire archicratique des
|
||||||
|
révolutions industrielles"
|
||||||
|
credit: ""
|
||||||
|
ts: 2026-02-25T19:11:32.634Z
|
||||||
|
fromIssue: 121
|
||||||
Reference in New Issue
Block a user