[claude] Live staging + auto-refresh on push (#33) (#34)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled
Co-authored-by: Claude (Opus 4.6) <claude@hermes.local> Co-committed-by: Claude (Opus 4.6) <claude@hermes.local>
This commit was merged in pull request #34.
This commit is contained in:
26
.gitea/workflows/deploy.yml
Normal file
26
.gitea/workflows/deploy.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: Deploy Nexus
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to host via SSH
|
||||||
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.DEPLOY_HOST }}
|
||||||
|
username: ${{ secrets.DEPLOY_USER }}
|
||||||
|
key: ${{ secrets.DEPLOY_SSH_KEY }}
|
||||||
|
script: |
|
||||||
|
cd ~/the-nexus || git clone http://143.198.27.163:3000/Timmy_Foundation/the-nexus.git ~/the-nexus
|
||||||
|
cd ~/the-nexus
|
||||||
|
git fetch origin main
|
||||||
|
git reset --hard origin/main
|
||||||
|
./deploy.sh main
|
||||||
6
Dockerfile
Normal file
6
Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
COPY . /usr/share/nginx/html
|
||||||
|
RUN rm -f /usr/share/nginx/html/Dockerfile \
|
||||||
|
/usr/share/nginx/html/docker-compose.yml \
|
||||||
|
/usr/share/nginx/html/deploy.sh
|
||||||
|
EXPOSE 80
|
||||||
17
deploy.sh
Executable file
17
deploy.sh
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# deploy.sh — spin up (or update) the Nexus staging environment
|
||||||
|
# Usage: ./deploy.sh — rebuild and restart nexus-main (port 4200)
|
||||||
|
# ./deploy.sh staging — rebuild and restart nexus-staging (port 4201)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SERVICE="${1:-nexus-main}"
|
||||||
|
|
||||||
|
case "$SERVICE" in
|
||||||
|
staging) SERVICE="nexus-staging" ;;
|
||||||
|
main) SERVICE="nexus-main" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "==> Deploying $SERVICE …"
|
||||||
|
docker compose build "$SERVICE"
|
||||||
|
docker compose up -d --force-recreate "$SERVICE"
|
||||||
|
echo "==> Done. Container: $SERVICE"
|
||||||
20
docker-compose.yml
Normal file
20
docker-compose.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
nexus-main:
|
||||||
|
build: .
|
||||||
|
container_name: nexus-main
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "4200:80"
|
||||||
|
labels:
|
||||||
|
- "deployment=main"
|
||||||
|
|
||||||
|
nexus-staging:
|
||||||
|
build: .
|
||||||
|
container_name: nexus-staging
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "4201:80"
|
||||||
|
labels:
|
||||||
|
- "deployment=staging"
|
||||||
50
index.html
50
index.html
@@ -120,5 +120,55 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script type="module" src="./app.js"></script>
|
<script type="module" src="./app.js"></script>
|
||||||
|
|
||||||
|
<!-- Live Refresh: polls Gitea for new commits on main, reloads when SHA changes -->
|
||||||
|
<div id="live-refresh-banner" style="
|
||||||
|
display:none; position:fixed; top:0; left:0; right:0; z-index:9999;
|
||||||
|
background:linear-gradient(90deg,#4af0c0,#7b5cff);
|
||||||
|
color:#050510; font-family:'JetBrains Mono',monospace; font-size:13px;
|
||||||
|
padding:8px 16px; text-align:center; font-weight:600;
|
||||||
|
">⚡ NEW DEPLOYMENT DETECTED — Reloading in <span id="lr-countdown">5</span>s…</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
const GITEA = 'http://143.198.27.163:3000/api/v1';
|
||||||
|
const REPO = 'Timmy_Foundation/the-nexus';
|
||||||
|
const BRANCH = 'main';
|
||||||
|
const INTERVAL = 30000; // poll every 30s
|
||||||
|
|
||||||
|
let knownSha = null;
|
||||||
|
|
||||||
|
async function fetchLatestSha() {
|
||||||
|
try {
|
||||||
|
const r = await fetch(`${GITEA}/repos/${REPO}/branches/${BRANCH}`, { cache: 'no-store' });
|
||||||
|
if (!r.ok) return null;
|
||||||
|
const d = await r.json();
|
||||||
|
return d.commit && d.commit.id ? d.commit.id : null;
|
||||||
|
} catch (e) { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function poll() {
|
||||||
|
const sha = await fetchLatestSha();
|
||||||
|
if (!sha) return;
|
||||||
|
if (knownSha === null) { knownSha = sha; return; }
|
||||||
|
if (sha !== knownSha) {
|
||||||
|
knownSha = sha;
|
||||||
|
const banner = document.getElementById('live-refresh-banner');
|
||||||
|
const countdown = document.getElementById('lr-countdown');
|
||||||
|
banner.style.display = 'block';
|
||||||
|
let t = 5;
|
||||||
|
const tick = setInterval(() => {
|
||||||
|
t--;
|
||||||
|
countdown.textContent = t;
|
||||||
|
if (t <= 0) { clearInterval(tick); location.reload(); }
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start polling after page is interactive
|
||||||
|
fetchLatestSha().then(sha => { knownSha = sha; });
|
||||||
|
setInterval(poll, INTERVAL);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user