Files
Scott Lamb 43d8a7e43a build fix: pin pnpm, move build-script approvals to pnpm-workspace.yaml
CI installed pnpm unpinned (`npm i -g pnpm`), so it picked up pnpm 11 --
released 2026-04-28, after v0.7.31 built fine on pnpm 10 -- and the Node
24 job failed with ERR_PNPM_IGNORED_BUILDS. pnpm 11 changed the default
of `strictDepBuilds` to true, so unapproved dependency build scripts are
a hard error rather than a warning.

Approve them in pnpm-workspace.yaml. pnpm 11 removed
`onlyBuiltDependencies` in favor of `allowBuilds`, and no longer reads
settings from the `pnpm` field of package.json at all; see
https://github.com/pnpm/pnpm/releases/tag/v11.0.0. The `packages` entry
keeps older pnpm from rejecting the file outright ("packages field
missing or empty").

Pin the pnpm version in both workflows so the next major doesn't land
unannounced; pnpm 12 is already in release candidates.

Drop Node 20 from the CI matrix. It reached end-of-life 2026-04-30, and
pnpm 11 requires Node >= 22.13 -- on Node 20 it dies with
ERR_UNKNOWN_BUILTIN_MODULE, so that job could not have passed anyway.
2026-08-14 17:57:23 -07:00

159 lines
5.9 KiB
YAML

name: Release
defaults:
run:
shell: bash
env:
DOCKER_TAG: "ghcr.io/${{ github.repository }}:${{ github.ref_name }}"
on:
push:
tags:
- v[0-9]+.*
jobs:
base:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: taiki-e/install-action@v2
with:
tool: parse-changelog
- name: Generate changelog
run: |
VERSION_MINUS_V=${GITHUB_REF_NAME/#v/}
parse-changelog CHANGELOG.md $VERSION_MINUS_V > CHANGELOG-$GITHUB_REF_NAME.md
- uses: actions/setup-node@v6
with:
node-version: 24
# Keep this pin in sync with ci.yml.
- run: npm i -g pnpm@11.21.0
- run: cd ui && pnpm i --frozen-lockfile
- run: cd ui && pnpm run build
- run: cd ui && pnpm run test
# Upload the UI and changelog as *job* artifacts (not *release* artifacts), used below.
- uses: actions/upload-artifact@v6
with:
name: moonfire-nvr-ui-${{ github.ref_name }}
path: ui/dist
if-no-files-found: error
- uses: actions/upload-artifact@v6
with:
name: CHANGELOG-${{ github.ref_name }}
path: CHANGELOG-${{ github.ref_name }}.md
if-no-files-found: error
cross:
needs: base # for bundled ui
permissions:
contents: read
packages: write
strategy:
matrix:
include:
# Note: keep these arches in sync with `Upload Docker Manifest` list.
- arch: x86_64 # as in `uname -m` on Linux.
rust_target: x86_64-unknown-linux-musl # as in <https://doc.rust-lang.org/rustc/platform-support.html>
docker_platform: linux/amd64 # as in <https://docs.docker.com/build/building/multi-platform/>
- arch: aarch64
rust_target: aarch64-unknown-linux-musl
docker_platform: linux/arm64
- arch: armv7l
rust_target: armv7-unknown-linux-musleabihf
docker_platform: linux/arm/v7
fail-fast: false
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download UI
uses: actions/download-artifact@v7
with:
name: moonfire-nvr-ui-${{ github.ref_name }}
path: ui/dist
# actions-rust-cross doesn't actually use cross for x86_64.
# Install the needed musl-tools in the host.
- name: Install musl-tools
run: sudo apt-get --option=APT::Acquire::Retries=3 update && sudo apt-get --option=APT::Acquire::Retries=3 install musl-tools
if: matrix.rust_target == 'x86_64-unknown-linux-musl'
- name: Build
uses: houseabsolute/actions-rust-cross@v1
env:
UI_BUILD_DIR: ../ui/dist
# cross doesn't install `git` within its Docker container, so plumb
# the version through rather than try `git describe` from `build.rs`.
VERSION: ${{ github.ref_name }}
with:
working-directory: server
target: ${{ matrix.rust_target }}
command: build
args: --release --features bundled,mimalloc
- name: Upload Docker Artifact
run: |
tag="${DOCKER_TAG}-${{ matrix.arch }}"
mkdir output
# We want a `/var/tmp` that any user can write to.
# Dockerfile's `COPY` doesn't preserve permissions on directories.
# But `ADD` does when expanding tarfiles. Prep a "filesystem skeleton" tar.
mkdir -p fs-skel/var/tmp
chmod 1777 fs-skel/var/tmp
tar cf output/fs-skel.tar --owner=0 --group=0 --directory=fs-skel .
tar tvf output/fs-skel.tar
ln ./server/target/${{ matrix.rust_target }}/release/moonfire-nvr output/
echo ${{secrets.GITHUB_TOKEN}} | docker login --username ${{github.actor}} --password-stdin ghcr.io
docker build --platform ${{ matrix.docker_platform }} --provenance=false --push --tag "${tag}" --file - output <<EOF
FROM scratch
LABEL org.opencontainers.image.title="Moonfire NVR"
LABEL org.opencontainers.image.description="security camera network video recorder"
LABEL org.opencontainers.image.source="https://github.com/${{ github.repository }}"
LABEL org.opencontainers.image.version="${{ github.ref_name }}"
ADD fs-skel.tar /
COPY --chmod=755 ./moonfire-nvr /usr/local/bin/moonfire-nvr
ENTRYPOINT ["/usr/local/bin/moonfire-nvr"]
EOF
# Upload as a *job* artifact (not *release* artifact), used below.
- name: Upload Job Artifact
uses: actions/upload-artifact@v6
with:
name: moonfire-nvr-${{ github.ref_name }}-${{ matrix.arch }}
path: output/moonfire-nvr
if-no-files-found: error
release:
needs: [base, cross]
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/download-artifact@v7
with:
path: artifacts
- name: ls before rearranging
run: find . -ls
- name: Rearrange
run: |
(cd artifacts/moonfire-nvr-ui-${GITHUB_REF_NAME} && zip -r ../../moonfire-nvr-ui-${GITHUB_REF_NAME}.zip .)
(cd artifacts; for i in moonfire-nvr-*/moonfire-nvr; do mv $i "../$(dirname $i)"; done)
- name: ls after rearranging
run: find . -ls
- name: Upload Docker Manifest (ghcr.io)
run: |
echo ${{secrets.GITHUB_TOKEN}} | docker login --username ${{github.actor}} --password-stdin ghcr.io
# Note: keep these arches in sync with `cross` job matrix.
docker manifest create "$DOCKER_TAG" "${DOCKER_TAG}"-{x86_64,aarch64,armv7l}
docker manifest push "$DOCKER_TAG"
- name: Create GitHub release
uses: softprops/action-gh-release@v2
with:
body_path: artifacts/CHANGELOG-${{ github.ref_name }}/CHANGELOG-${{ github.ref_name }}.md
files: |
moonfire-nvr-*