name: Build & Deploy on: push: branches: [main] workflow_dispatch: jobs: build-and-deploy: runs-on: freebsd steps: - uses: actions/checkout@v4 - name: Install dependencies run: npm ci - name: Build or restore sharp for FreeBSD run: | SHARP_VER=$(node -e "process.stdout.write(require('./node_modules/sharp/package.json').version)") CACHE_FILE=/usr/local/git/.cache/sharp-freebsd/sharp-freebsd-x64-${SHARP_VER}.node if [ -f "$CACHE_FILE" ]; then echo "Restoring cached sharp ${SHARP_VER}" mkdir -p node_modules/sharp/src/build/Release cp "$CACHE_FILE" node_modules/sharp/src/build/Release/sharp-freebsd-x64.node else echo "Building sharp ${SHARP_VER} from source..." npm install node-addon-api node-gyp npm install sharp --build-from-source mkdir -p /usr/local/git/.cache/sharp-freebsd BUILT=$(find node_modules/sharp -name "sharp-freebsd-x64.node" | head -1) if [ -n "$BUILT" ]; then cp "$BUILT" "$CACHE_FILE" echo "Cached sharp binary at $CACHE_FILE" fi fi - name: Fetch homepage config from node jail run: | mkdir -p ~/.ssh printf '%s\n' "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa mkdir -p content/.indiekit ssh -p 222 -o StrictHostKeyChecking=no \ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \ "sudo bastille cmd node cat /usr/local/indiekit/content/.indiekit/homepage.json" \ > content/.indiekit/homepage.json - name: Build CSS run: npm run build:css - name: Create .env file env: SITE_URL: ${{ secrets.SITE_URL }} SITE_NAME: ${{ secrets.SITE_NAME }} SITE_SOCIAL: ${{ secrets.SITE_SOCIAL }} AUTHOR_NAME: ${{ secrets.AUTHOR_NAME }} SITE_DESCRIPTION: ${{ secrets.SITE_DESCRIPTION }} AUTHOR_BIO: ${{ secrets.AUTHOR_BIO }} AUTHOR_EMAIL: ${{ secrets.AUTHOR_EMAIL }} AUTHOR_LOCATION: ${{ secrets.AUTHOR_LOCATION }} GITHUB_USERNAME: ${{ secrets.GH_USERNAME }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} MASTODON_USER: ${{ secrets.MASTODON_USER }} BLUESKY_HANDLE: ${{ secrets.BLUESKY_HANDLE }} ACTIVITYPUB_HANDLE: ${{ secrets.ACTIVITYPUB_HANDLE }} AUTHOR_AVATAR: ${{ secrets.AUTHOR_AVATAR }} AUTHOR_TITLE: ${{ secrets.AUTHOR_TITLE }} AUTHOR_PRONOUN: ${{ secrets.AUTHOR_PRONOUN }} SITE_LOCALE: ${{ secrets.SITE_LOCALE }} OWNYOURSWARM_FEED_URL: ${{ secrets.OWNYOURSWARM_FEED_URL }} OWNYOURSWARM_FEED_TOKEN: ${{ secrets.OWNYOURSWARM_FEED_TOKEN }} LISTENING_FETCH_CACHE_DURATION: ${{ secrets.LISTENING_FETCH_CACHE_DURATION }} FUNKWHALE_FETCH_CACHE_DURATION: ${{ secrets.FUNKWHALE_FETCH_CACHE_DURATION }} LASTFM_FETCH_CACHE_DURATION: ${{ secrets.LASTFM_FETCH_CACHE_DURATION }} run: | { printf 'SITE_URL=%s\n' "$SITE_URL" printf 'SITE_NAME=%s\n' "$SITE_NAME" printf 'SITE_SOCIAL=%s\n' "$SITE_SOCIAL" printf 'AUTHOR_NAME=%s\n' "$AUTHOR_NAME" printf 'SITE_DESCRIPTION=%s\n' "$SITE_DESCRIPTION" printf 'AUTHOR_BIO=%s\n' "$AUTHOR_BIO" printf 'AUTHOR_EMAIL=%s\n' "$AUTHOR_EMAIL" printf 'AUTHOR_LOCATION=%s\n' "$AUTHOR_LOCATION" printf 'GITHUB_USERNAME=%s\n' "$GITHUB_USERNAME" printf 'MASTODON_INSTANCE=%s\n' "$MASTODON_INSTANCE" printf 'MASTODON_USER=%s\n' "$MASTODON_USER" printf 'BLUESKY_HANDLE=%s\n' "$BLUESKY_HANDLE" printf 'ACTIVITYPUB_HANDLE=%s\n' "$ACTIVITYPUB_HANDLE" printf 'AUTHOR_AVATAR=%s\n' "$AUTHOR_AVATAR" printf 'AUTHOR_TITLE=%s\n' "$AUTHOR_TITLE" printf 'AUTHOR_PRONOUN=%s\n' "$AUTHOR_PRONOUN" printf 'SITE_LOCALE=%s\n' "$SITE_LOCALE" printf 'OWNYOURSWARM_FEED_URL=%s\n' "$OWNYOURSWARM_FEED_URL" printf 'OWNYOURSWARM_FEED_TOKEN=%s\n' "$OWNYOURSWARM_FEED_TOKEN" printf 'LISTENING_FETCH_CACHE_DURATION=%s\n' "$LISTENING_FETCH_CACHE_DURATION" printf 'FUNKWHALE_FETCH_CACHE_DURATION=%s\n' "$FUNKWHALE_FETCH_CACHE_DURATION" printf 'LASTFM_FETCH_CACHE_DURATION=%s\n' "$LASTFM_FETCH_CACHE_DURATION" } > .env - name: Build site run: npm run build env: SITE_URL: ${{ secrets.SITE_URL }} SITE_NAME: ${{ secrets.SITE_NAME }} SITE_SOCIAL: ${{ secrets.SITE_SOCIAL }} SITE_DESCRIPTION: ${{ secrets.SITE_DESCRIPTION }} AUTHOR_NAME: ${{ secrets.AUTHOR_NAME }} ACTIVITYPUB_HANDLE: ${{ secrets.ACTIVITYPUB_HANDLE }} AUTHOR_AVATAR: ${{ secrets.AUTHOR_AVATAR }} AUTHOR_BIO: ${{ secrets.AUTHOR_BIO }} AUTHOR_EMAIL: ${{ secrets.AUTHOR_EMAIL }} GITHUB_USERNAME: ${{ secrets.GH_USERNAME }} MASTODON_INSTANCE: ${{ secrets.MASTODON_INSTANCE }} MASTODON_USER: ${{ secrets.MASTODON_USER }} BLUESKY_HANDLE: ${{ secrets.BLUESKY_HANDLE }} GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} OWNYOURSWARM_FEED_URL: ${{ secrets.OWNYOURSWARM_FEED_URL }} OWNYOURSWARM_FEED_TOKEN: ${{ secrets.OWNYOURSWARM_FEED_TOKEN }} LISTENING_FETCH_CACHE_DURATION: ${{ secrets.LISTENING_FETCH_CACHE_DURATION }} FUNKWHALE_FETCH_CACHE_DURATION: ${{ secrets.FUNKWHALE_FETCH_CACHE_DURATION }} LASTFM_FETCH_CACHE_DURATION: ${{ secrets.LASTFM_FETCH_CACHE_DURATION }} INDIEKIT_URL: http://10.100.0.20:3000 FUNKWHALE_INSTANCE: http://10.100.0.40:5000 GITEA_URL: https://gitea.giersig.eu GITEA_INTERNAL_URL: http://127.0.0.1:3000 GITEA_ORG: giersig.eu - name: Deploy via rsync run: | mkdir -p ~/.ssh printf '%s\n' "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -p 222 ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null cp .env _site/.env rsync -rlz --delete \ --exclude='content/.indiekit/' \ -e "ssh -p 222" \ _site/ \ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/usr/local/bastille/jails/web/root/usr/local/www/blog/ - name: Trigger syndication webhook env: SECRET: ${{ secrets.SECRET }} SITE_URL: ${{ secrets.SITE_URL }} INDIEKIT_INTERNAL_URL: http://10.100.0.20:3000 run: | npm install --no-save jsonwebtoken TOKEN=$(node --input-type=commonjs <<'EOF' const jwt = require('jsonwebtoken'); const token = jwt.sign( { me: process.env.SITE_URL, scope: 'update' }, process.env.SECRET, { expiresIn: '10m' } ); process.stdout.write(token); EOF ) RESPONSE=$(curl -sS -w "\n%{http_code}" -X POST \ -H "Content-Type: application/json" \ -d "{\"access_token\": \"$TOKEN\"}" \ "$INDIEKIT_INTERNAL_URL/syndicate") HTTP_CODE=$(echo "$RESPONSE" | tail -1) BODY=$(echo "$RESPONSE" | sed '$d') echo "HTTP $HTTP_CODE: $BODY" [ "$HTTP_CODE" -lt 400 ]