diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml new file mode 100644 index 0000000..905d785 --- /dev/null +++ b/.forgejo/workflows/deploy.yml @@ -0,0 +1,116 @@ +name: Deploy Better Life SG + +on: + push: + branches: [master] + workflow_dispatch: + +concurrency: + group: deploy-betterlifesg-${{ forgejo.ref }} + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Configure SSH + shell: bash + env: + VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }} + run: | + set -euo pipefail + install -d -m 700 ~/.ssh + python3 - <<'PY' + import os + from pathlib import Path + + key = os.environ["VPS_SSH_KEY"] + if "\\n" in key and "\n" not in key: + key = key.replace("\\n", "\n") + key = key.replace("\r\n", "\n").replace("\r", "\n").strip() + "\n" + Path.home().joinpath(".ssh", "id_ed25519").write_text(key, encoding="utf-8") + PY + chmod 600 ~/.ssh/id_ed25519 + ssh-keygen -y -f ~/.ssh/id_ed25519 >/dev/null + ssh-keyscan -H 23.226.133.245 >> ~/.ssh/known_hosts + + - name: Deploy on VPS + shell: bash + run: | + set -euo pipefail + ssh root@23.226.133.245 "cd /opt/src/betterlifesg && bash scripts/deploy-betterlifesg.sh" + + notify: + if: ${{ always() }} + needs: [deploy] + runs-on: ubuntu-latest + steps: + - name: Send ntfy notification + shell: bash + env: + JOB_RESULTS: ${{ toJson(needs) }} + NTFY_TOKEN: ${{ secrets.NTFY_TOKEN }} + NTFY_TOPIC_URL: https://ntfy.bytesizeprotip.com/deploy + RUN_URL: ${{ forgejo.server_url }}/${{ forgejo.repository }}/actions/runs/${{ forgejo.run_id }} + run: | + set -euo pipefail + + if [ -z "$NTFY_TOKEN" ]; then + echo "NTFY_TOKEN secret not configured, skipping notification." + exit 0 + fi + + eval "$(python3 - <<'PY' + import json + import os + import shlex + + needs = json.loads(os.environ["JOB_RESULTS"]) + results = {name: str(data.get("result") or "unknown") for name, data in needs.items()} + has_failure = any(result == "failure" for result in results.values()) + has_cancelled = any(result == "cancelled" for result in results.values()) + + if has_failure: + status = "failure" + priority = "5" + tags = "rotating_light,x" + elif has_cancelled: + status = "cancelled" + priority = "4" + tags = "warning" + else: + status = "success" + priority = "2" + tags = "white_check_mark" + + summary = ", ".join(f"{name}:{result}" for name, result in results.items()) or "no upstream jobs" + message = "\n".join([ + f"Repo: {os.environ['FORGEJO_REPOSITORY']}", + f"Workflow: {os.environ['FORGEJO_WORKFLOW']}", + f"Status: {status}", + f"Ref: {os.environ.get('FORGEJO_REF_NAME', '')}", + f"Actor: {os.environ.get('FORGEJO_ACTOR', '')}", + f"Run: {os.environ['RUN_URL']}", + f"Jobs: {summary}", + ]) + + values = { + "NTFY_TITLE": f"{os.environ['FORGEJO_WORKFLOW']} {status}", + "NTFY_PRIORITY": priority, + "NTFY_TAGS": tags, + "NTFY_MESSAGE": message, + } + + for key, value in values.items(): + print(f"{key}={shlex.quote(value)}") + PY + )" + + curl --fail --show-error --silent \ + -H "Authorization: Bearer $NTFY_TOKEN" \ + -H "Title: $NTFY_TITLE" \ + -H "Priority: $NTFY_PRIORITY" \ + -H "Tags: $NTFY_TAGS" \ + -H "Click: $RUN_URL" \ + -d "$NTFY_MESSAGE" \ + "$NTFY_TOPIC_URL" \ No newline at end of file diff --git a/README.md b/README.md index 594837f..697f97a 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,18 @@ Static website for Better Life SG insurance consultants, replicated from betterl ## Deployment +Push to `master` in Forgejo to deploy automatically via Forgejo Actions. + ```bash ssh racknerd bash /opt/src/betterlifesg/scripts/deploy-betterlifesg.sh ``` +## Forgejo Actions + +- Trigger: push to `master` and manual `workflow_dispatch` +- Required secret: `VPS_SSH_KEY` +- Optional secret: `NTFY_TOKEN` + ## Managed by BetterBot The site content can be edited via the BetterBot Telegram bot (see `betterbot/` repo).