Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
517e77f
add gh actions workflow for building rpi image
mickmister Feb 5, 2025
95dab19
upload-artifact@v4
mickmister Feb 5, 2025
3cf7a51
try again
mickmister Feb 5, 2025
fbdd72f
run in pr
mickmister Feb 5, 2025
2b99412
try from example https://github.com/RaspAP/raspap-webgui/blob/master/…
mickmister Feb 5, 2025
2a8d518
remove custom stage
mickmister Feb 5, 2025
784a314
mkdir /proc etc.
mickmister Feb 5, 2025
b22aff8
re-add custom stage
mickmister Feb 5, 2025
6d00c40
copy+paste pre-existing workflow
mickmister Feb 5, 2025
781f722
make workflow run in pr
mickmister Feb 5, 2025
d1cb765
try increase-runner-disk-size
mickmister Feb 5, 2025
60c2642
copy existing workflow directly
mickmister Feb 10, 2025
0448ab5
change to run on PRs
mickmister Feb 10, 2025
a805730
use actions/upload-artifact
mickmister Feb 10, 2025
1868adf
take workflow from jamtools/raspap-webgui
mickmister Feb 10, 2025
cea722a
Create build_rpi.yml to test release workflow trigger
mickmister Feb 14, 2025
16d78e7
add chroot workflow
mickmister Mar 28, 2025
5050274
Merge branch 'gh-actions-rpi-image' of github.com:jamtools/rpi-deploy…
mickmister Mar 28, 2025
2520422
introduce updatecli tool
mickmister Apr 14, 2025
15320a7
support watching esbuild and GH releases through systemd
mickmister Apr 14, 2025
5bd390d
more solidified gh release watcher
mickmister Apr 14, 2025
0b1cb3f
several updates to clean up unstaged changes
mickmister Apr 19, 2025
e8220df
add FullPageOS
mickmister Aug 19, 2025
11a0586
copy rpi-deploy folder to FullPageOS filesystem
mickmister Aug 19, 2025
0a77a94
change start_chroot_script to be more rpi-deploy focused
mickmister Aug 19, 2025
b9de19e
replace ci workflow with custompios
mickmister Aug 19, 2025
1144277
change image architecture
mickmister Aug 19, 2025
0b26384
change /home/jamtools to /home/pi
mickmister Aug 19, 2025
01b3e87
Create claude.yml
mickmister Sep 1, 2025
d613263
Create claude.yml
mickmister Sep 1, 2025
ce2eefa
remove claude.yml
mickmister Sep 1, 2025
1e97de6
Merge branch 'main' into gh-actions-rpi-image
mickmister Sep 1, 2025
c4370d6
disable build_rpi.yml by making it only run through workflow_dispatch
mickmister Sep 1, 2025
6bcfbcb
Convert build workflow to reusable composite action
claude[bot] Sep 1, 2025
2c7f6e2
Remove test workflow due to permissions
claude[bot] Sep 1, 2025
51d4199
move GH action steps around
mickmister Sep 1, 2025
d61550d
edit workflow to use new action
mickmister Sep 1, 2025
56afc83
fix composite action calling
mickmister Sep 1, 2025
2304d65
find/replace jamtools user with pi
mickmister Sep 1, 2025
e14dc64
Parameterize UpdateCLI configuration and ensure GITHUB_TOKEN availabi…
claude[bot] Sep 1, 2025
23321cb
Fix version stripping in GitHub action to prevent double 'v' prefix
claude[bot] Sep 1, 2025
70f09d8
move some files around
mickmister Sep 1, 2025
54bf257
Merge branch 'gh-actions-rpi-image' of github.com:jamtools/rpi-deploy…
mickmister Sep 1, 2025
a7a6f6f
delete old folder
mickmister Sep 1, 2025
5733b98
support esbuild for dev
mickmister Sep 1, 2025
8674bf2
skip "test" ci job
mickmister Sep 1, 2025
df056f3
rename ci job
mickmister Sep 1, 2025
72c79aa
rename ci artifact
mickmister Sep 1, 2025
05059e3
include rpi-deploy module when building custompios
mickmister Sep 1, 2025
0c76669
change updatecli arch
mickmister Sep 2, 2025
fabb5a7
unpack as pi user
mickmister Sep 2, 2025
a3874a2
install better_sqlite3 and easymidi during image build
mickmister Sep 2, 2025
4327f6b
fix pakcage name typo
mickmister Sep 2, 2025
f1658ed
fix substitution issues. add more gh action args for customization
mickmister Sep 3, 2025
d7498ac
upgrade node to v22
mickmister Sep 3, 2025
1d7fd70
fix variable substitutions for real
mickmister Sep 3, 2025
0357628
rename GITHB_RELEASES_TOKEN to GH_RELEASES_TOKEN
mickmister Sep 3, 2025
0cb9111
ad commit to trigger ci
mickmister Jan 5, 2026
4615f5b
use "chromium" instead of "chromium-browser"
mickmister Jan 6, 2026
57e9f6b
Merge branch 'gh-actions-rpi-image' of github.com:jamtools/rpi-deploy…
mickmister Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 206 additions & 0 deletions .github/actions/build-rpi-image/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
name: 'Build RPi Image with Release Download'
description: 'Downloads latest release from a repo and builds a Raspberry Pi image'
inputs:
source_repo:
description: 'GitHub repository to download release from (e.g., owner/repo)'
required: true
version_prefix:
description: 'Version tag prefix to match releases (e.g., vapp-)'
required: true
gh_releases_token:
description: 'GitHub token for API access'
required: true
default: ${{ github.token }}
service_name:
description: 'Name of the service to create'
required: false
default: 'myapp'
esbuild_server_url:
description: 'URL of esbuild development server (enables esbuild mode when provided)'
required: false
chroot_commands:
description: 'Additional commands to run in chroot environment (multiline string)'
required: false
default: ''
service_command:
description: 'Command to run for the service (e.g., "/usr/bin/node /home/pi/code/artifacts/dist/server/dist/local-server.cjs")'
required: false
default: '/usr/bin/node /home/pi/code/artifacts/dist/server/dist/local-server.cjs'

runs:
using: 'composite'
steps:

- name: Free up disk space
uses: insightsengineering/disk-space-reclaimer@v1
with:
android: true
dotnet: true
haskell: true
large-packages: false
swap-storage: true
docker-images: true
tools-cache: false

- name: Check disk space
shell: bash
run: df -h

- name: Update apt
shell: bash
run: sudo apt-get update

- name: Install Dependencies
shell: bash
run: sudo apt install coreutils p7zip-full qemu-user-static python3-git

- name: Find latest matching release by tag prefix
id: find_release
shell: bash
env:
GH_TOKEN: ${{ inputs.gh_releases_token }}
run: |
PREFIX="${{ inputs.version_prefix }}"
latest=$(gh release list --repo "${{ inputs.source_repo }}" --limit 100 --json tagName,publishedAt \
| jq -r --arg prefix "$PREFIX" '
map(select(.tagName | startswith($prefix)))
| sort_by(.publishedAt)
| last
| if . == null then "none" else .tagName[1:] end
')
echo "latest_tag=$latest" >> $GITHUB_OUTPUT
echo "Found latest release: $latest"

- name: Download artifact from latest release
if: steps.find_release.outputs.latest_tag != 'none'
uses: blauqs/actions-download-asset@master
with:
repo: ${{ inputs.source_repo }}
version: ${{ steps.find_release.outputs.latest_tag }}
file: dist.zip
out: previous_release.zip
token: ${{ inputs.gh_releases_token }}

- name: Checkout CustomPiOS
uses: actions/checkout@v2
with:
repository: 'guysoft/CustomPiOS'
path: CustomPiOS

- name: Checkout Project Repository
uses: actions/checkout@v2
with:
repository: ${{ github.repository }}
path: repository_temp
submodules: true

- name: Move FullPageOS folder
shell: bash
run: |
mv repository_temp/FullPageOS repository

- name: Place downloaded release zip
if: steps.find_release.outputs.latest_tag != 'none'
shell: bash
run: |
# Create the directory structure where updatecli expects the zip file on the RPi
mkdir -p repository/src/modules/rpi-deploy/filesystem/home/pi/code/artifacts/
# Move the downloaded zip to where the updatecli scripts expect it
mv previous_release.zip repository/src/modules/rpi-deploy/filesystem/home/pi/code/artifacts/dist.zip
echo "Placed release zip at: repository/src/modules/rpi-deploy/filesystem/home/pi/code/artifacts/dist.zip"

- name: Parameterize UpdateCLI configuration
shell: bash
run: |
# Extract owner and repository from source_repo input
OWNER=$(echo "${{ inputs.source_repo }}" | cut -d'/' -f1)
REPOSITORY=$(echo "${{ inputs.source_repo }}" | cut -d'/' -f2)

# Create the directory for secrets
mkdir -p repository/src/modules/rpi-deploy/filesystem/home/pi/code/

# Create secrets.env file with GH_RELEASES_TOKEN and SERVICE_NAME
echo "GH_RELEASES_TOKEN=${{ inputs.gh_releases_token }}" > repository/src/modules/rpi-deploy/filesystem/home/pi/code/secrets.env
echo "SERVICE_NAME=${{ inputs.service_name }}" >> repository/src/modules/rpi-deploy/filesystem/home/pi/code/secrets.env

# Parameterize the updatecli configuration file
UPDATECLI_CONFIG="repository/src/modules/rpi-deploy/filesystem/home/pi/code/updatecli_github_commit.yml"

# Replace template variables using envsubst
export GITHUB_OWNER="$OWNER"
export GITHUB_REPOSITORY="$REPOSITORY"
export GITHUB_VERSION_PREFIX="${{ inputs.version_prefix }}"
export GITHUB_TAG_PREFIX="${GITHUB_VERSION_PREFIX}"

# Process the template file
envsubst '$GITHUB_OWNER $GITHUB_REPOSITORY $GITHUB_TAG_PREFIX' < "$UPDATECLI_CONFIG" > "$UPDATECLI_CONFIG.tmp"
mv "$UPDATECLI_CONFIG.tmp" "$UPDATECLI_CONFIG"

# Export additional template variables
export CHROOT_COMMANDS="${{ inputs.chroot_commands }}"
export SERVICE_COMMAND="${{ inputs.service_command }}"

# Process start_chroot_script template
CHROOT_SCRIPT="repository/src/modules/rpi-deploy/start_chroot_script"
envsubst '$CHROOT_COMMANDS' < "$CHROOT_SCRIPT" > "$CHROOT_SCRIPT.tmp"
mv "$CHROOT_SCRIPT.tmp" "$CHROOT_SCRIPT"

# Process run_from_github_release.sh template
RELEASE_SCRIPT="repository/src/modules/rpi-deploy/filesystem/home/pi/code/scripts/run_from_github_release.sh"
envsubst '$SERVICE_COMMAND' < "$RELEASE_SCRIPT" > "$RELEASE_SCRIPT.tmp"
mv "$RELEASE_SCRIPT.tmp" "$RELEASE_SCRIPT"

# Configure esbuild if server URL is provided
if [ -n "${{ inputs.esbuild_server_url }}" ]; then
echo "ESBUILD_SERVER_URL=${{ inputs.esbuild_server_url }}" >> repository/src/modules/rpi-deploy/filesystem/home/pi/code/esbuild.env
echo "SERVICE_NAME=${{ inputs.service_name }}-dev" >> repository/src/modules/rpi-deploy/filesystem/home/pi/code/esbuild.env

# Enable esbuild service in start_chroot_script
sed -i 's/# systemctl enable check_esbuild.service/systemctl enable check_esbuild.service/' repository/src/modules/rpi-deploy/start_chroot_script

echo "Esbuild mode enabled:"
echo " Server URL: ${{ inputs.esbuild_server_url }}"
echo " Service name: ${{ inputs.service_name }}-dev"
fi

echo "Updated UpdateCLI config with:"
echo " Owner: $OWNER"
echo " Repository: $REPOSITORY"
echo " Version prefix: ${{ inputs.version_prefix }}"
echo " Service name: ${{ inputs.service_name }}"
if [ -n "${{ inputs.esbuild_server_url }}" ]; then
echo " Esbuild mode: enabled"
else
echo " Esbuild mode: disabled (GitHub releases only)"
fi

- name: Download Raspbian Image
shell: bash
run: cd repository/src/image && wget -q -c --trust-server-names 'https://downloads.raspberrypi.org/raspios_lite_armhf_latest'

- name: Update CustomPiOS Paths
shell: bash
run: cd repository/src && ../../CustomPiOS/src/update-custompios-paths

- name: Build Image
shell: bash
run: sudo modprobe loop && cd repository/src && sudo BASE_ARCH=armhf bash -x ./build_dist

- name: Copy Output
shell: bash
run: cp ${{ github.workspace }}/repository/src/workspace/*-raspios-*-lite.img build.img

- name: Zip Output
shell: bash
run: gzip build.img

- name: Set artifact name
id: artifact
shell: bash
run: echo "name=$(date '+%Y%m%d_%H%M%S')_${{ github.sha }}_$(echo '${{ inputs.source_repo }}' | tr '/' '_')_rpi.img.gz" >> $GITHUB_OUTPUT

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.artifact.outputs.name }}
path: build.img.gz
40 changes: 40 additions & 0 deletions .github/workflows/build_rpi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Dispatched Build and publish RaspAP images

permissions:
contents: write

on:
workflow_dispatch:

jobs:
build-raspap-image:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- arch: "32-bit"
pi_gen_version: "master"
- arch: "64-bit"
pi_gen_version: "arm64"
fail-fast: false
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Build RaspAP Image
id: build
uses: usimd/pi-gen-action@v1
with:
image-name: "raspap-bookworm-${{ matrix.arch == '32-bit' && 'armhf' || 'arm64' }}-lite-${{ github.event.inputs.tag || github.ref_name }}"
enable-ssh: 1
stage-list: stage0 stage1 stage2
# stage-list: stage0 stage1 stage2 ./stage-raspap
verbose-output: true
pi-gen-version: ${{ matrix.pi_gen_version }}
pi-gen-repository: RaspAP/pi-gen

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: rpi-deploy-${{ matrix.arch }}.img.zip
path: ${{ steps.build.outputs.image-path }}
25 changes: 25 additions & 0 deletions .github/workflows/build_with_custompios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Build Image
Copy link
Member Author

@mickmister mickmister Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude Change this into an action that can be called instead of a workflow. But have a workflow that tests the action with parameters “jamtools/jamscribe” as the GitHub repo and “vjamscribe-“ as the version prefix.

The action should get the latest release of the passed in repo, download its artifacts, put the zip file where it’s supposed to go (where the updatecli files in this repo are expecting it). And then build the rpi image using the rest of the logic in this existing workflow.

Use these steps to handle the release download:

 name: Find latest matching release by tag prefix
      id: find_release
      env:
        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        PREFIX="vjamscribe-" # Claude make this configurable
        latest=$(gh release list --repo "${{ github.repository }}" --limit 100 --json tagName,publishedAt \ # Claude make the repo configurable
          | jq -r --arg prefix "$PREFIX" '
              map(select(.tagName | startswith($prefix)))
              | sort_by(.publishedAt)
              | last
              | if . == null then "none" else .tagName[1:] end
            ')
        echo "latest_tag=$latest" >> $GITHUB_OUTPUT

    - name: Download artifact from latest release
      if: steps.find_release.outputs.latest_tag != 'none'
      uses: blauqs/actions-download-asset@master
      with:
        repo: ${{ github.repository }} # Claude make configurable
        version: ${{ steps.find_release.outputs.latest_tag }}
        file: dist.zip
        out: previous_release.zip
        token: ${{ secrets.GITHUB_TOKEN }}

Copy link

@claude claude bot Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @mickmister's task —— View job


Converting Workflow to Reusable Action ✅

I've successfully converted the build workflow into a reusable GitHub composite action with configurable parameters.

Todo List:

  • Read current workflow file and understand structure
  • Check for CLAUDE.md repository guidelines
  • Create composite action with configurable repo and version prefix
  • Create test workflow that calls the action with specified parameters (Unable due to workflow permissions)
  • Ensure proper zip file placement for updatecli
  • Test and commit changes

What I've Created

Composite Action (.github/actions/build-rpi-image/action.yml):

  • Configurable inputs:

    • source_repo: GitHub repository to download release from (e.g., "jamtools/jamscribe")
    • version_prefix: Version tag prefix to match releases (e.g., "vjamscribe-")
    • github_token: GitHub token for API access (defaults to ${{ github.token }})
  • Key features:

    • Finds latest release matching the version prefix using gh CLI and jq
    • Downloads the dist.zip artifact from the latest matching release
    • Places the zip file at the correct path for updatecli scripts: /home/jamtools/code/artifacts/dist.zip
    • Builds the RPi image using the existing CustomPiOS logic
    • Includes all the original build steps (disk cleanup, dependencies, etc.)

Usage

To use this action in a workflow, create a workflow file like:

name: Test RPi Image Build Action

on: workflow_dispatch

jobs:
  test-action:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Build RPi Image
        uses: ./.github/actions/build-rpi-image
        with:
          source_repo: 'jamtools/jamscribe'
          version_prefix: 'vjamscribe-'
          github_token: ${{ secrets.GITHUB_TOKEN }}

Note: I couldn't create the test workflow file due to GitHub App permission restrictions on workflow modifications. You'll need to create this workflow file manually if you want to test the action.

The composite action is ready to use and properly handles the release download logic you specified, with the zip file placement matching what your updatecli scripts expect.

--- | Branch: gh-actions-rpi-image


on: push

jobs:
build-image:
runs-on: ubuntu-latest
steps:
- name: Checkout releases repo into `.github/composite-actions`
uses: actions/checkout@v3
with:
repository: jamtools/rpi-deploy
path: .github/composite-actions
ref: ${{ github.sha }}

- name: Build RPi Image
uses: ./.github/composite-actions/.github/actions/build-rpi-image
with:
source_repo: 'jamtools/jamscribe'
version_prefix: 'vjamscribe-'
gh_releases_token: ${{ secrets.GH_RELEASES_TOKEN }}
service_name: 'jamscribe'
service_command: '/usr/bin/node /home/pi/code/artifacts/dist/server/dist/local-server.cjs'
chroot_commands: |
npm i better-sqlite3 easymidi
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
run: npm run check-types

test:
# skip tests for now
if: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand Down
63 changes: 63 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Claude Code

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@beta
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read

# Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4)
# model: "claude-opus-4-20250514"

# Optional: Customize the trigger phrase (default: @claude)
# trigger_phrase: "/claude"

# Optional: Trigger when specific user is assigned to an issue
# assignee_trigger: "claude-bot"

# Optional: Allow Claude to run specific commands
# allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"

# Optional: Add custom instructions for Claude to customize its behavior for your project
# custom_instructions: |
# Follow our coding standards
# Ensure all new code has tests
# Use TypeScript for new files

# Optional: Custom environment variables for Claude
# claude_env: |
# NODE_ENV: test
19 changes: 19 additions & 0 deletions FullPageOS/.github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#### What were you doing?

[Please be as specific as possible here]

#### What did you expect to happen?

#### What happened instead?

#### Was there an error message displayed? What did it say?

#### Version of FullPageOS?

[Can be found in /etc/fullpageos_version ALWAYS INCLUDE.]

#### Screenshot(s) showing the problem:

[If applicable. Always include if unsure or reporting UI issues.]

#### If you are building FullPageOS - provide a build.log that is created for the build
Loading
Loading