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:
parent
4768edc67b
commit
7e7fd74b40
2 changed files with 444 additions and 0 deletions
236
.github/workflows/nightly.yml
vendored
Normal file
236
.github/workflows/nightly.yml
vendored
Normal 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
|
||||
208
docs/research/nightly-build-research.md
Normal file
208
docs/research/nightly-build-research.md
Normal 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
|
||||
Loading…
Add table
Reference in a new issue