Neocities Deploy from GitHub Actions
A CI workflow to lint and build, a CD workflow to deploy to Neocities, and a brief defense of why I build the site twice.
I redesigned my Neocities site to lean harder into a GeoCities look. While I was in there, I wanted a deploy process simple enough to run from my iPad.
Neocities is dead-simple hosting for static sites. Bret Comnes already built a GitHub Action for deploying to it, so the hard part was done. I just wanted a clean test run before pointing it at the live site.
ci.yml runs Prettier over the code and builds the site. It fires on any push to main, any pull request, or a manual trigger.
name: CI
# I wanted the CI to run on any push to main, pull request, or
# manually triggered.
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-latest
steps:
- id: checkout
name: π₯ Checkout code
uses: actions/checkout@v4
with:
lfs: true
- id: setup-node
name: βοΈ Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: "npm"
- id: install-dependencies
name: π¦ Install dependencies
run: npm ci
- id: cache-dependencies
name: π Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- id: prettier-check
name: π
Run Prettier check
run: npm run prettier
# In the future I'll probably add `astro check` support
# here: <https://docs.astro.build/en/guides/typescript/#type-checking>
- id: build
name: ποΈ Build website
run: npm run build
cd.yml does the actual deploy. It hooks into the workflow_run event, which fires whenever CI finishes, and only proceeds if that run succeeded on main.
name: CD
# I want the CD to only run if CI succeeded on main.
on:
workflow_run:
branches: ["main"]
types: ["completed"]
workflows: ["CI"]
# It would be nice if we can only allow this to be deployed
# from `main`, but GitHub doesn't support that right now.
workflow_dispatch:
concurrency:
group: cd
cancel-in-progress: true
jobs:
cd:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- id: checkout
name: π₯ Checkout code
uses: actions/checkout@v4
with:
lfs: true
- id: setup-node
name: βοΈ Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: "npm"
- id: install-dependencies
name: π¦ Install dependencies
run: npm ci
- id: cache-dependencies
name: π Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- id: build
name: ποΈ Build website
run: npm run build
- id: deploy
name: π Deploy to Neocities
uses: bcomnes/deploy-to-neocities@v3
with:
api_key: ${{ secrets.NEOCITIES_API_TOKEN }}
cleanup: false
neocities_supporter: true
preview_before_deploy: true
dist_dir: dist/
Yes, thatβs two builds. CD rebuilds instead of pulling CIβs output so I can run the deploy on its own when I need to, without depending on a CI run existing.
If you want to see the full code, itβs all open source on the GitHub repository.