name: refresh # Daily re-bake of the prerendered site. The crawler-visible HTML is a static # snapshot taken at build time; this job rebuilds it from the current gist (CV) # and activity API and redeploys *only* the web tier — so edits propagate to # what crawlers and AI screeners see without a code push and without bouncing # the api/worker. Humans already get live data via post-hydration refetch. # # Uses the same gitea_ci + scoped-sudo path as deploy.yml's deploy-web job; # see asset/sudoers.d/web-host.conf and script/infra-setup.sh. on: schedule: # 04:17 UTC daily — off-peak, arbitrary minute to avoid the top-of-hour herd. - cron: '17 4 * * *' workflow_dispatch: concurrency: group: deploy # share the deploy lock so a refresh never races a push deploy cancel-in-progress: false env: WEB_HOST: oolon.kosherinata.internal SERVER_NAME: rob.tn WEB_ROOT: /var/www/rob.tn API_PORT: "42424" API_UPSTREAM_SCHEME: http API_UPSTREAM_ADDR: nikola.kosherinata.internal:42424 VITE_API_BASE: https://rob.tn/api/v1 DEPLOY_KEY: | ${{ secrets.RSYNC_SSH_KEY }} jobs: build-web: name: Rebuild prerendered web runs-on: fedora-44 # image bakes in node + pnpm; that's all we need here steps: - uses: actions/checkout@v4 # Install without the pnpm 10 build-script gate, then rebuild the native # deps vite needs (see deploy.yml build-web for the rationale). - name: Build web (vite client + prerender) working-directory: ui run: | pnpm install --frozen-lockfile --ignore-scripts pnpm rebuild @swc/core esbuild pnpm run build - uses: actions/upload-artifact@v3 with: { name: web-dist, path: ui/dist, retention-days: 1 } deploy-web: name: Deploy refreshed web to oolon needs: build-web runs-on: fedora-44 steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v3 with: { name: web-dist, path: dist } - name: SSH init run: | mkdir -p ~/.ssh echo "${DEPLOY_KEY}" > ~/.ssh/id_ed25519 chmod 600 ~/.ssh/id_ed25519 ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new \ gitea_ci@"${WEB_HOST}" 'hostname -f' - name: Render nginx vhost run: | mkdir -p rendered python3 - <<'PY' import os t = open("asset/nginx/site.conf.tmpl").read() for k in ("SERVER_NAME", "API_UPSTREAM_SCHEME", "API_UPSTREAM_ADDR"): t = t.replace("{{%s}}" % k, os.environ[k]) t = t.replace("{{DOCROOT}}", os.environ["WEB_ROOT"]) open("rendered/site.conf", "w").write(t) PY - name: Sync static site (prerendered) run: | ssh gitea_ci@"${WEB_HOST}" 'sudo /usr/bin/install -d -m 0755 '"${WEB_ROOT}" rsync -az --delete --mkpath --rsync-path='sudo rsync' \ --chown=root:root --chmod=D755,F644 \ dist/ gitea_ci@"${WEB_HOST}":"${WEB_ROOT}/" ssh gitea_ci@"${WEB_HOST}" 'sudo /usr/sbin/restorecon -R '"${WEB_ROOT}" - name: Sync nginx vhost + reload run: | rsync -az --mkpath --rsync-path='sudo rsync' --chown=root:root --chmod=0644 \ rendered/site.conf \ gitea_ci@"${WEB_HOST}":/etc/nginx/conf.d/"${SERVER_NAME}".conf ssh gitea_ci@"${WEB_HOST}" ' set -euo pipefail sudo /usr/sbin/setsebool -P httpd_can_network_connect on if ! sudo /usr/sbin/semanage port -l | grep -E "^http_port_t" | grep -qw '"${API_PORT}"'; then sudo /usr/sbin/semanage port -a -t http_port_t -p tcp '"${API_PORT}"' fi sudo /usr/sbin/restorecon -R /etc/nginx/conf.d/'"${SERVER_NAME}"'.conf sudo /usr/sbin/nginx -t sudo /usr/bin/systemctl reload nginx'