Skip to content

chore: track hooks in .githooks/, update CI to dev, add commit-msg ho… #211

chore: track hooks in .githooks/, update CI to dev, add commit-msg ho…

chore: track hooks in .githooks/, update CI to dev, add commit-msg ho… #211

# ═══════════════════════════════════════════════════════════

Check failure on line 1 in .github/workflows/build-and-publish.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/build-and-publish.yml

Invalid workflow file

(Line: 31, Col: 3): 'push' is already defined
# LocalPibox Devstack — CI/CD Build & Publish
# ═══════════════════════════════════════════════════════════
# Builds on GitHub (fast connection) → publishes to GHCR
# Extensions update at runtime via pi update --extensions
#
# Triggers:
# - Push to dev (Dockerfile, support/, lpb.stack.env, lpb.conf.env)
# - Push to main only from LPB version tags (0.*-lpb, 1.*-lpb)
# - Weekly cron (Monday 3am UTC) — keep image fresh
# - Manual dispatch
#
# Build tags:
# - dev branch: :dev, :dev-cli, :dev-web, :{sha}-cli, :{sha}-web
# - tag push: :{version}-cli, :{version}-web
# - latest: only on manual dispatch or schedule
# - weekly: :weekly-cli, :weekly-web
name: Build & Publish Devstack
on:
push:
branches: [dev]
paths:
- 'Dockerfile'
- 'support/**'
- 'lpb.stack.env'
- 'lpb.conf.env'
- '.github/workflows/*.yml'
- 'scripts/**'
push:
tags:
- '0.*-lpb'
- '1.*-lpb'
paths:
- 'VERSION'
- 'lpb.stack.env'
pull_request:
branches: [dev]
paths:
- 'Dockerfile'
- 'support/**'
- 'lpb.stack.env'
- 'lpb.conf.env'
- '.github/workflows/*.yml'
- 'scripts/**'
schedule:
- cron: '0 3 * * 1'
workflow_dispatch:
inputs:
publish_latest:
description: 'Publish as :latest tag'
type: boolean
default: true
no_cache:
description: 'Full rebuild with no cache (pick up fork-branch changes)'
type: boolean
default: false
permissions:
contents: read
packages: write
env:
IMAGE_NAME: ghcr.io/localpibox/devstack
jobs:
test-lpb:
name: Run lpb.py unit tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Run test suite
run: |
python3 scripts/test_lpb.py
python3 scripts/test_localpibox.py
build-cli:
name: Build & publish cli image
runs-on: ubuntu-latest
timeout-minutes: 45
needs: [test-lpb]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up buildx
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Load stack config
id: config
run: |
set -a
source lpb.stack.env
set +a
echo "PI_FORK=$LPB_PI_FORK" >> "$GITHUB_OUTPUT"
echo "PI_REF=$LPB_PI_REF" >> "$GITHUB_OUTPUT"
echo "CONFIG_FORK=$LPB_CONFIG_FORK" >> "$GITHUB_OUTPUT"
echo "CONFIG_REF=$LPB_CONFIG_REF" >> "$GITHUB_OUTPUT"
echo "NODE_VERSION=$LPB_NODE_VERSION" >> "$GITHUB_OUTPUT"
echo "VSCODIUM_VERSION=$LPB_VSCODIUM_VERSION" >> "$GITHUB_OUTPUT"
echo "LPB_VERSION=$(cat VERSION 2>/dev/null || echo unknown)" >> "$GITHUB_OUTPUT"
MAX_TOKENS=$(grep -E '^LPB_MAX_TOKENS_CONTEXT_RATIO=' lpb.conf.env | cut -d= -f2- | tr -d '"' 2>/dev/null || true)
echo "MAX_TOKENS=${MAX_TOKENS:-0.06}" >> "$GITHUB_OUTPUT"
sha=$(git ls-remote "$LPB_PI_FORK" "refs/heads/$LPB_PI_REF" | awk '{print $1}')
# Read stack version from config repo
cfg_repo=$(echo "$LPB_CONFIG_FORK" | sed -E 's#https://github.com/([^/]+)/([^./]+)\.git#\1/\2#')
stack_ver=$(curl -sf "https://raw.githubusercontent.com/$cfg_repo/$LPB_CONFIG_REF/VERSION" 2>/dev/null || echo "unknown")
echo "sha=${sha:-unknown}" >> "$GITHUB_OUTPUT"
echo "stack_version=${stack_ver}" >> "$GITHUB_OUTPUT"
- name: Build & push cli
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: cli
push: ${{ github.event_name != 'pull_request' }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
PI_FORK=${{ steps.config.outputs.PI_FORK }}
PI_REF=${{ steps.config.outputs.PI_REF }}
CONFIG_FORK=${{ steps.config.outputs.CONFIG_FORK }}
CONFIG_REF=${{ steps.config.outputs.CONFIG_REF }}
NODE_VERSION=${{ steps.config.outputs.NODE_VERSION }}
VSCODIUM_VERSION=${{ steps.config.outputs.VSCODIUM_VERSION }}
PI_HEAD_SHA=${{ steps.config.outputs.sha }}
LPB_VERSION=${{ steps.config.outputs.LPB_VERSION }}
LPB_MAX_TOKENS_CONTEXT_RATIO=${{ steps.config.outputs.MAX_TOKENS }}
no-cache: ${{ github.event.inputs.no_cache == 'true' }}
tags: |
${{ env.IMAGE_NAME }}:dev
${{ env.IMAGE_NAME }}:dev-cli
${{ env.IMAGE_NAME }}:${{ github.sha }}-cli
${{ env.IMAGE_NAME }}:${{ steps.config.outputs.stack_version }}-cli
${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && format('{0}:{1}-cli', env.IMAGE_NAME, github.ref_name) || '' }}
${{ github.event.inputs.publish_latest && format('{0}:latest-cli', env.IMAGE_NAME) || '' }}
${{ github.event_name == 'schedule' && format('{0}:weekly-cli', env.IMAGE_NAME) || '' }}
provenance: false
platforms: linux/amd64
build-web:
name: Build & publish web image
runs-on: ubuntu-latest
timeout-minutes: 45
needs: [build-cli]
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up buildx
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Load stack config
id: config
run: |
set -a
source lpb.stack.env
set +a
echo "PI_FORK=$LPB_PI_FORK" >> "$GITHUB_OUTPUT"
echo "PI_REF=$LPB_PI_REF" >> "$GITHUB_OUTPUT"
echo "CONFIG_FORK=$LPB_CONFIG_FORK" >> "$GITHUB_OUTPUT"
echo "CONFIG_REF=$LPB_CONFIG_REF" >> "$GITHUB_OUTPUT"
echo "NODE_VERSION=$LPB_NODE_VERSION" >> "$GITHUB_OUTPUT"
echo "VSCODIUM_VERSION=$LPB_VSCODIUM_VERSION" >> "$GITHUB_OUTPUT"
echo "LPB_VERSION=$(cat VERSION 2>/dev/null || echo unknown)" >> "$GITHUB_OUTPUT"
MAX_TOKENS=$(grep -E '^LPB_MAX_TOKENS_CONTEXT_RATIO=' lpb.conf.env | cut -d= -f2- | tr -d '"' 2>/dev/null || true)
echo "MAX_TOKENS=${MAX_TOKENS:-0.06}" >> "$GITHUB_OUTPUT"
sha=$(git ls-remote "$LPB_PI_FORK" "refs/heads/$LPB_PI_REF" | awk '{print $1}')
# Read stack version from config repo
cfg_repo=$(echo "$LPB_CONFIG_FORK" | sed -E 's#https://github.com/([^/]+)/([^./]+)\.git#\1/\2#')
stack_ver=$(curl -sf "https://raw.githubusercontent.com/$cfg_repo/$LPB_CONFIG_REF/VERSION" 2>/dev/null || echo "unknown")
echo "sha=${sha:-unknown}" >> "$GITHUB_OUTPUT"
echo "stack_version=${stack_ver}" >> "$GITHUB_OUTPUT"
- name: Build & push web
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
target: web
push: ${{ github.event_name != 'pull_request' }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
PI_FORK=${{ steps.config.outputs.PI_FORK }}
PI_REF=${{ steps.config.outputs.PI_REF }}
CONFIG_FORK=${{ steps.config.outputs.CONFIG_FORK }}
CONFIG_REF=${{ steps.config.outputs.CONFIG_REF }}
NODE_VERSION=${{ steps.config.outputs.NODE_VERSION }}
VSCODIUM_VERSION=${{ steps.config.outputs.VSCODIUM_VERSION }}
PI_HEAD_SHA=${{ steps.config.outputs.sha }}
LPB_VERSION=${{ steps.config.outputs.LPB_VERSION }}
LPB_MAX_TOKENS_CONTEXT_RATIO=${{ steps.config.outputs.MAX_TOKENS }}
no-cache: ${{ github.event.inputs.no_cache == 'true' }}
tags: |
${{ env.IMAGE_NAME }}:dev
${{ env.IMAGE_NAME }}:dev-web
${{ env.IMAGE_NAME }}:${{ github.sha }}-web
${{ env.IMAGE_NAME }}:${{ steps.config.outputs.stack_version }}-web
${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && format('{0}:{1}-web', env.IMAGE_NAME, github.ref_name) || '' }}
${{ github.event.inputs.publish_latest && format('{0}:latest-web', env.IMAGE_NAME) || '' }}
${{ github.event_name == 'schedule' && format('{0}:weekly-web', env.IMAGE_NAME) || '' }}
provenance: false
platforms: linux/amd64
status:
name: Build status
needs: [build-cli, build-web]
if: always()
runs-on: ubuntu-latest
steps:
- run: |
if [ "${{ needs.build-cli.result }}" != "success" ] || [ "${{ needs.build-web.result }}" != "success" ]; then
echo "Build failed!"
exit 1
fi
echo "Build complete — both cli and web images pushed"