Files
Nathan Schneider 346c859eb5 Hugo site with Woodpecker CI -> Surfer deploy pipeline
Builds the site with hugomods/hugo:dart-sass-node-git and syncs public/
to the Surfer app on the same Cloudron server (surfer put --all --delete).
README covers full setup: Gitea OAuth app, Woodpecker env.sh forge config,
agent options, and repo secrets.
2026-10-02 17:37:36 -06:00

54 lines
2.4 KiB
YAML

# Build the Hugo site and push the result to Surfer (both apps on the same Cloudron).
#
# Docs:
# Workflow syntax: https://woodpecker-ci.org/docs/usage/workflow-syntax
# Surfer CLI: https://docs.cloudron.io/packages/surfer/#cli-tool
#
# Repo secrets expected in Woodpecker (Settings -> Secrets):
# surfer_server - Surfer app domain, e.g. surfer.cloudron.example (no scheme)
# surfer_token - access token created in the Surfer admin UI (/_admin)
when:
# Deploy on pushes to main only. Other branches never build or deploy.
- event: push
branch: main
# Also allow "Run pipeline" in the Woodpecker UI (redeploying without a push).
# If you use this, make sure the two secrets below are also allowed for the
# "manual" event, not just push.
- event: manual
steps:
# 1) Build the site into ./public
#
# hugomods/hugo variants: https://docker.hugomods.com/
# `dart-sass-node-git` is the maintained "everything" image: extended Hugo +
# Node/yarn + Git + Dart Sass. Pin a version with, for example,
# hugomods/hugo:dart-sass-node-git-0.165.0 (and drop `pull: true`).
- name: build
image: hugomods/hugo:dart-sass-node-git
pull: true
commands:
- hugo --minify --gc
# 2) Upload ./public to Surfer
- name: deploy
image: node:24-alpine
environment:
# Where on the Surfer server the site lives.
# "/" - the site is served at the Surfer app's domain root
# "/mysite/" - served in a subdirectory (keep baseURL in hugo.toml in sync!)
SURFER_DEST: /
SURFER_SERVER:
from_secret: surfer_server
SURFER_TOKEN:
from_secret: surfer_token
commands:
- npm install --global cloudron-surfer
# public/* (not public) so the CONTENTS of public/ end up in $SURFER_DEST -
# `surfer put public /` would upload a literal "public" folder instead.
# --all also includes hidden files nested inside those dirs, and --delete removes remote files that are no longer in public/
# (a real sync, so renamed assets don't pile up on the server).
- surfer put --all --delete --token "$SURFER_TOKEN" --server "$SURFER_SERVER" public/* "$SURFER_DEST"
# Optional: top-level dot directories (e.g. .well-known/) are skipped by the
# shell glob above, so re-sync them explicitly without --delete:
# - if [ -d public/.well-known ]; then surfer put --token "$SURFER_TOKEN" --server "$SURFER_SERVER" public/.well-known "$SURFER_DEST"; fi