Feat/nightly build (#2)

* feat: add nightly build workflow

- Add nightly.yml GitHub Actions workflow for daily builds
- Schedule: daily at 2 AM UTC
- Build using GoReleaser snapshot mode
- Upload artifacts to GitHub Releases as pre-release
- Create nightly Docker tags
- Clean old nightly releases (keep last 30)
- Add research documentation for nightly build setup

* fix: correct yaml syntax error in nightly workflow

* feat: restore nightly build workflow

---------

Co-authored-by: Hua <zhangmikoto@gmail.com>
This commit is contained in:
Hua Audio 2026-03-07 21:35:04 +01:00 committed by GitHub
parent 4768edc67b
commit 7e7fd74b40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 444 additions and 0 deletions

236
.github/workflows/nightly.yml vendored Normal file
View file

@ -0,0 +1,236 @@
name: Nightly Build
on:
schedule:
# Run every day at 00:00 UTC
- cron: '0 0 * * *'
workflow_dispatch:
# Allow manual triggering
inputs:
skip_version:
description: 'Skip version generation (use current)'
required: false
default: 'false'
type: boolean
build_only:
description: 'Build only, skip release'
required: false
default: 'false'
type: boolean
env:
CARGO_TERM_COLOR: always
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
generate-version:
name: Generate Nightly Version
runs-on: ubuntu-latest
if: github.event.inputs.skip_version != 'true'
outputs:
version: ${{ steps.version.outputs.version }}
tag: ${{ steps.version.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate nightly version
id: version
run: |
# Get current date
DATE=$(date +%Y%m%d)
# Get short commit hash
SHA=$(git rev-parse --short HEAD)
# Generate version: v0.1.0-nightly-YYYYMMDD-sha
VERSION="v0.1.0-nightly-${DATE}-${SHA}"
TAG="nightly-${DATE}-${SHA}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "Generated version: ${VERSION}"
echo "Generated tag: ${TAG}"
build:
name: Build Picoclaw
runs-on: ubuntu-latest
needs: generate-version
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
cache: true
- name: Build binary
run: |
go build -v -o picoclaw .
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: picoclaw-linux-amd64
path: picoclaw
build-docker:
name: Build Docker Image
runs-on: ubuntu-latest
needs: generate-version
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=nightly-{{date 'YYYYMMDD'}},priority=100
type=raw,value=nightly,priority=90
type=sha,prefix={{branch}}-,priority=50
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
create-release:
name: Create Nightly Release
runs-on: ubuntu-latest
needs: [generate-version, build]
if: github.event.inputs.build_only != 'true'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: picoclaw-linux-amd64
path: ./artifacts
- name: Prepare release notes
run: |
cat > release_notes.md << 'EOF'
# Picoclaw Nightly Release
📅 **Date**: $(date -u +'%Y-%m-%d %H:%M:%S UTC')
🏷️ **Version**: ${{ needs.generate-version.outputs.version }}
🌿 **Branch**: ${{ github.ref_name }}
🔗 **Commit**: ${{ github.sha }}
---
## 📦 Download
### Linux AMD64 Binary
- `picoclaw-linux-amd64` - Pre-built binary for Linux x86_64
### Docker Image
```bash
docker pull ghcr.io/${{ github.repository }}:nightly-$(date +%Y%m%d)
# or latest nightly
docker pull ghcr.io/${{ github.repository }}:nightly
```
---
## 🔧 Installation
### Using binary
```bash
chmod +x picoclaw
sudo mv picoclaw /usr/local/bin/
```
### Using Docker
```bash
docker run -d --name picoclaw \
-v /path/to/config:/config \
ghcr.io/${{ github.repository }}:nightly
```
---
## ⚠️ Disclaimer
This is a **nightly build** and may contain:
- Unfinished features
- Bugs and instability
- Breaking changes
For production use, please use a stable release instead.
---
🦞 **Built with ❤️ by Picoclaw**
EOF
- name: Create GitHub Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
VERSION: ${{ needs.generate-version.outputs.version }}
TAG: ${{ needs.generate-version.outputs.tag }}
run: |
gh release create "$TAG" \
--title "$VERSION" \
--notes-file release_notes.md \
./artifacts/picoclaw-linux-amd64
- name: Update nightly tag reference
if: success()
run: |
# Update 'nightly' tag to point to latest nightly
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -f nightly ${{ github.sha }}
git push origin nightly --force
- name: Clean up old nightly releases (keep last 7)
if: success()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# List all nightly releases, keep only the 7 most recent
gh release list --limit 100 | grep nightly- | tail -n +8 | awk '{print $3}' | xargs -I {} gh release delete --yes --cleanup-tag {}
notify:
name: Notify Results
runs-on: ubuntu-latest
needs: [build-docker, create-release]
if: always()
steps:
- name: Check build status
run: |
if [ "${{ needs.create-release.result }}" == "success" ]; then
echo "✅ Nightly build completed successfully!"
echo "Version: ${{ needs.generate-version.outputs.version }}"
else
echo "❌ Nightly build failed"
echo "Check the workflow logs for details"
fi

View file

@ -0,0 +1,208 @@
# Picoclaw Nightly Build Research
## Repository Overview
**Repository**: https://github.com/sipeed/picoclaw
**Current Branch**: `main`
**Latest Commit**: `66e6fb6`
### Project Structure
```
picoclaw/
├── .github/workflows/ # GitHub Actions workflows
│ ├── build.yml # CI build on push to main
│ ├── pr.yml # PR validation
│ ├── release.yml # Release workflow (manual trigger)
│ └── upload-tos.yml # Upload to Volcengine TOS
├── .goreleaser.yaml # GoReleaser configuration
├── Makefile # Build targets
├── go.mod # Go 1.25.7
├── cmd/ # Main entry points
│ ├── picoclaw/ # Main binary
│ ├── picoclaw-launcher/ # Web launcher
│ └── picoclaw-launcher-tui/ # TUI launcher
├── pkg/ # Core packages
│ ├── agent/ # Agent logic
│ ├── auth/ # Authentication
│ ├── channels/ # Communication channels
│ ├── config/ # Configuration
│ ├── memory/ # Memory management
│ ├── providers/ # LLM providers
│ ├── skills/ # Skills system
│ └── tools/ # Tool functions
├── docker/ # Docker configurations
└── docs/ # Documentation
```
## Existing Workflows
### 1. build.yml
- **Trigger**: Push to `main`
- **Action**: Builds picoclaw using `make build-all`
- **Platform**: Ubuntu latest
### 2. release.yml
- **Trigger**: Manual workflow dispatch
- **Actions**:
- Creates git tag
- Runs GoReleaser to build for all platforms
- Uploads to GitHub Releases
- Optionally uploads to TOS
- **Platforms**: Linux, Windows, Darwin, FreeBSD (amd64, arm64, riscv64, loong64, arm)
- **Docker**: Multi-platform builds to GHCR and DockerHub
### 3. pr.yml
- **Trigger**: Pull requests
- **Action**: PR validation (details not visible in current session)
### 4. upload-tos.yml
- **Trigger**: Called from release workflow
- **Action**: Uploads artifacts to Volcengine TOS
## Build System
### Makefile Targets
| Target | Description |
|--------|-------------|
| `build` | Build for current platform |
| `build-all` | Build for all platforms (8 variants) |
| `build-whatsapp-native` | Build with WhatsApp native support |
| `build-linux-arm` | Build for Linux ARMv7 |
| `build-linux-arm64` | Build for Linux ARM64 |
| `build-pi-zero` | Build for Raspberry Pi Zero 2 W |
| `install` | Install to `~/.local/bin` |
| `test` | Run tests |
| `lint` | Run golangci-lint |
| `docker-build` | Build minimal Docker image (Alpine) |
| `docker-build-full` | Build full Docker image (Node.js 24) |
### GoReleaser Configuration
**Builds:**
- `picoclaw` - Main binary
- `picoclaw-launcher` - Web launcher
- `picoclaw-launcher-tui` - TUI launcher
**Target Platforms:**
- OS: Linux, Windows, Darwin, FreeBSD
- Arch: amd64, arm64, riscv64, loong64, arm (v6, v7)
**Docker Images:**
- `ghcr.io/<owner>/picoclaw`
- `docker.io/<repository>`
- Platforms: linux/amd64, linux/arm64, linux/riscv64
## Nightly Build Requirements
### Goals
1. Build daily snapshots of the `main` branch
2. Upload artifacts to GitHub Releases (as pre-release)
3. Optionally build and push Docker images
4. Keep limited number of nightly builds (cleanup old ones)
### Design Decisions
| Decision | Rationale |
|----------|-----------|
| **Cron Schedule**: `0 2 * * *` (2 AM UTC) | Off-peak hours, allows testing during business day |
| **Release Type**: Pre-release | Clearly distinguishes from stable releases |
| **Tag Format**: `nightly-YYYYMMDD` | Easy to identify and sort by date |
| **Artifact Retention**: 30 days | Balance between availability and storage |
| **Docker Tags**: `nightly`, `nightly-YYYYMMDD` | Allow both latest and pinned versions |
## Proposed Nightly.yml Workflow
```yaml
name: Nightly Build
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM UTC
workflow_dispatch: # Allow manual trigger
jobs:
nightly:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
- name: Set nightly tag
id: tag
run: |
NIGHTLY_TAG="nightly-$(date +%Y%m%d)"
echo "tag=$NIGHTLY_TAG" >> $GITHUB_OUTPUT
- name: Create/Update nightly tag
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -f "${{ steps.tag.outputs.tag }}"
git push -f origin "${{ steps.tag.outputs.tag }}"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser (snapshot)
uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: ~> v2
args: release --clean --snapshot
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NIGHTLY_TAG: ${{ steps.tag.outputs.tag }}
DOCKERHUB_IMAGE_NAME: ${{ vars.DOCKERHUB_REPOSITORY }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: nightly-artifacts
path: dist/
- name: Clean old nightly releases
run: |
# Keep only last 30 nightly releases
gh release list \
--query "[startsWith(name, 'nightly-')] | [30:].[].name" \
--json name \
-t '{{ range . }}{{ .name }}{{ "\n" }}{{ end }}' \
| xargs -I {} gh release delete {} --yes || true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## Notes
1. **Security**: No secrets required for basic nightly builds
2. **Storage**: GitHub provides 2GB free storage; implement cleanup if needed
3. **Testing**: Nightly builds serve as canary builds for testing
4. **Docker**: Can optionally push `nightly` Docker tags
5. **Notifications**: Could add Slack/discord notifications on failure
## References
- GoReleaser docs: https://goreleaser.com/
- GitHub Actions docs: https://docs.github.com/en/actions
- Picoclaw docs: /docs/tools_configuration.md